├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── mayaConfigure.bat ├── modules └── FindMaya.cmake ├── pythonConfigure.bat ├── src ├── lib │ ├── combo.cpp │ ├── combo.h │ ├── enums.h │ ├── floater.h │ ├── progression.cpp │ ├── progression.h │ ├── shape.cpp │ ├── shape.h │ ├── shapeBase.h │ ├── shapeController.cpp │ ├── shapeController.h │ ├── simplex.cpp │ ├── simplex.h │ ├── slider.cpp │ ├── slider.h │ ├── traversal.cpp │ ├── traversal.h │ ├── trispace.cpp │ ├── trispace.h │ ├── utils.cpp │ └── utils.h ├── maya │ ├── pluginMain.cpp │ ├── simplex_mayaNode.cpp │ └── simplex_mayaNode.h ├── python │ └── simplex_python.cpp └── xsi │ ├── simplex_ice.cpp │ └── simplex_ice.h └── xsiConfigure.bat /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Release zipfile 6 | Simplex.zip 7 | 8 | # Build folders 9 | Maya20*/ 10 | **/build/ 11 | **/pybuild/ 12 | **/mayabuild/ 13 | **/mayabuild*/ 14 | **/xsibuild/ 15 | **/xsibuild*/ 16 | **/output/ 17 | **/output*/ 18 | **/Useful/ 19 | 20 | # VIM Swapfiles 21 | *.swp 22 | 23 | # Folder config file 24 | Desktop.ini 25 | 26 | # Recycle Bin used on file shares 27 | $RECYCLE.BIN/ 28 | 29 | # Windows Installer files 30 | *.cab 31 | *.msi 32 | *.msm 33 | *.msp 34 | 35 | #python bytecode 36 | *.pyc 37 | 38 | # Windows shortcuts 39 | *.lnk 40 | 41 | # ========================= 42 | # Operating System Files 43 | # ========================= 44 | 45 | # OSX 46 | # ========================= 47 | 48 | .DS_Store 49 | .AppleDouble 50 | .LSOverride 51 | 52 | # Thumbnails 53 | ._* 54 | 55 | # Files that might appear on external disk 56 | .Spotlight-V100 57 | .Trashes 58 | 59 | # Directories potentially created on remote AFP share 60 | .AppleDB 61 | .AppleDesktop 62 | Network Trash Folder 63 | Temporary Items 64 | .apdisk 65 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "include/eigen"] 2 | path = include/eigen 3 | url = https://github.com/eigenteam/eigen-git-mirror.git 4 | [submodule "include/rapidjson"] 5 | path = include/rapidjson 6 | url = https://github.com/Tencent/rapidjson.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/modules) 4 | set(TARGET_DCC Maya CACHE STRING "Target Content Creation Package: Maya XSI Python") 5 | 6 | include_directories(src/lib include/rapidjson/include include/eigen) 7 | 8 | file(GLOB SOURCE_FILES 9 | "src/lib/*.h" 10 | "src/lib/*.cpp" 11 | ) 12 | 13 | if (${TARGET_DCC} STREQUAL "Maya") 14 | project(simplex_maya) 15 | find_package(Maya REQUIRED) 16 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) 17 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/${MAYA_VERSION}) 18 | 19 | file(GLOB MAYA_FILES 20 | "src/maya/*.h" 21 | "src/maya/*.cpp" 22 | ) 23 | 24 | include_directories(${MAYA_INCLUDE_DIR}) 25 | link_directories(${MAYA_LIBRARY_DIR}) 26 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${MAYA_FILES}) 27 | target_link_libraries(${PROJECT_NAME} ${MAYA_LIBRARIES}) 28 | 29 | MAYA_PLUGIN(${PROJECT_NAME}) 30 | install(TARGETS ${PROJECT_NAME} DESTINATION blur/plug-ins) 31 | elseif(${TARGET_DCC} STREQUAL "XSI") 32 | project(simplex_ice) 33 | set(XSI_VERSION "2014 SP2" CACHE STRING "The XSI version") 34 | 35 | # XSI is dead, so not worth a cmake find 36 | # So, just set the data directly 37 | set(SI_HOME "C:/Program Files/Autodesk/Softimage ${XSI_VERSION}") 38 | set(XSISDK_ROOT ${SI_HOME}/XSISDK) 39 | set(XSI_LIB_DIR ${XSISDK_ROOT}/lib/nt-x86-64) 40 | 41 | set(XSI_INCLUDE_DIRS ${XSISDK_ROOT}/include) 42 | set(XSI_LIBRARIES 43 | "${XSI_LIB_DIR}/sicppsdk.lib" 44 | "${XSI_LIB_DIR}/sicoresdk.lib" 45 | ) 46 | 47 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/XSI${XSI_VERSION}) 48 | file(GLOB XSI_FILES 49 | "src/xsi/*.h" 50 | "src/xsi/*.cpp" 51 | ) 52 | include_directories(${XSI_INCLUDE_DIRS}) 53 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${XSI_FILES}) 54 | target_link_libraries(${PROJECT_NAME} ${XSI_LIBRARIES}) 55 | install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION plug-ins) 56 | elseif(${TARGET_DCC} STREQUAL "BlurPython") 57 | project(pysimplex) 58 | 59 | # Blergh, I can't do the normal find_package(PythonLibs REQUIRED) 60 | # we have to support 32 and 64 bit builds with strange paths 61 | # start annoying hard-coding 62 | set(PY_VERSION 27_64 CACHE STRING "The python version as part of the path") 63 | set(PY_PATH C:/Python${PY_VERSION}) 64 | string(REPLACE "_" ";" _PY_VLIST ${PY_VERSION}) 65 | list(GET _PY_VLIST 0 PY_SIMPLE_VERSION) 66 | set(PYTHON_INCLUDE_DIRS ${PY_PATH}/include) 67 | set(PYTHON_LIBRARIES ${PY_PATH}/libs/python${PY_SIMPLE_VERSION}.lib) 68 | # End annoying hard-coding 69 | 70 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/Python${PY_VERSION}) 71 | file(GLOB PY_FILES 72 | "src/python/*.h" 73 | "src/python/*.cpp" 74 | ) 75 | include_directories(${PYTHON_INCLUDE_DIRS}) 76 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${PY_FILES}) 77 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".pyd") 78 | 79 | if(WIN32) 80 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".pyd") 81 | else() 82 | set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") 83 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".so") 84 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/python${PY_VERSION}) 85 | endif() 86 | 87 | target_link_libraries(${PROJECT_NAME} ${PYTHON_LIBRARIES}) 88 | message("Python Libraries: ${PYTHON_LIBRARIES}") 89 | 90 | install(TARGETS ${PROJECT_NAME} 91 | RUNTIME DESTINATION lib 92 | ARCHIVE DESTINATION lib 93 | ) 94 | elseif(${TARGET_DCC} STREQUAL "Python") 95 | project(pysimplex) 96 | find_package(Python2 REQUIRED COMPONENTS Development) 97 | 98 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/Python${PY_VERSION}) 99 | file(GLOB PY_FILES 100 | "src/python/*.h" 101 | "src/python/*.cpp" 102 | ) 103 | include_directories(${Python2_INCLUDE_DIRS}) 104 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${PY_FILES}) 105 | if(WIN32) 106 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".pyd") 107 | else() 108 | set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") 109 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".x86_64-linux-gnu.so") 110 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/python${PY_VERSION}) 111 | endif() 112 | 113 | target_link_libraries(${PROJECT_NAME} ${Python2_LIBRARIES}) 114 | message("Python Libraries: ${Python2_LIBRARIES}") 115 | 116 | install(TARGETS ${PROJECT_NAME} 117 | RUNTIME DESTINATION lib 118 | ARCHIVE DESTINATION lib 119 | ) 120 | 121 | elseif(${TARGET_DCC} STREQUAL "Python3") 122 | project(pysimplex3) 123 | find_package(Python3 REQUIRED COMPONENTS Development) 124 | 125 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/Python${PY_VERSION}) 126 | file(GLOB PY_FILES 127 | "src/python/*.h" 128 | "src/python/*.cpp" 129 | ) 130 | include_directories(${Python3_INCLUDE_DIRS}) 131 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${PY_FILES}) 132 | if(WIN32) 133 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".pyd") 134 | else() 135 | set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") 136 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".x86_64-linux-gnu.so") 137 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../output/python${PY_VERSION}) 138 | endif() 139 | 140 | target_link_libraries(${PROJECT_NAME} ${Python3_LIBRARIES}) 141 | message("Python Libraries: ${Python3_LIBRARIES}") 142 | 143 | install(TARGETS ${PROJECT_NAME} 144 | RUNTIME DESTINATION lib 145 | ARCHIVE DESTINATION lib 146 | ) 147 | 148 | elseif(${TARGET_DCC} STREQUAL "Test") 149 | project(pysimplex) 150 | file(GLOB TEST_FILES 151 | "src/test/*.h" 152 | "src/test/*.cpp" 153 | ) 154 | add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${TEST_FILES}) 155 | else() 156 | message(FATAL_ERROR "Improper DCC Specified. Must be either Maya or XSI") 157 | endif() 158 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: \ 2 | help \ 3 | generate_maya \ 4 | generate_python \ 5 | generate_xsi \ 6 | build_maya \ 7 | build_python \ 8 | build_xsi \ 9 | install_maya \ 10 | install_python \ 11 | install_xsi \ 12 | clean \ 13 | 14 | 15 | CMAKE = cmake 16 | 17 | MAYA_VERSION = 2019 18 | MAYA_BUILD_DIR = mayabuild 19 | 20 | PYTHON_VERSION = 2.7 21 | PYTHON_BUILD_DIR = pybuild 22 | 23 | XSI_VERSION = 2015 24 | XSI_BUILD_DIR = xsibuild 25 | 26 | #-----------------------------------------------------------------------------# 27 | # cmake generate targets 28 | #-----------------------------------------------------------------------------# 29 | 30 | generate_maya:: 31 | rm -rf $(MAYA_BUILD_DIR) 32 | mkdir -p $(MAYA_BUILD_DIR) 33 | $(CMAKE) -DMAYA_VERSION=$(MAYA_VERSION) -B$(MAYA_BUILD_DIR) 34 | 35 | generate_python:: 36 | rm -rf $(PYTHON_BUILD_DIR) 37 | mkdir -p $(PYTHON_BUILD_DIR) 38 | $(CMAKE) -DPY_VERSION=$(PYTHON_VERSION) -DTARGET_DCC=Python -B$(PYTHON_BUILD_DIR) 39 | 40 | generate_xsi:: 41 | rm -rf $(XSI_BUILD_DIR) 42 | mkdir -p $(XSI_BUILD_DIR) 43 | $(CMAKE) -DXSI_VERSION=$(XSI_VERSION) -DTARGET_DCC=XSI -B$(XSI_BUILD_DIR) 44 | 45 | #-----------------------------------------------------------------------------# 46 | # cmake build targets 47 | #-----------------------------------------------------------------------------# 48 | 49 | build_maya:: 50 | cmake --build $(MAYA_BUILD_DIR) --config Release 51 | 52 | build_python:: 53 | cmake --build $(PYTHON_BUILD_DIR) --config Release 54 | 55 | build_xsi:: 56 | cmake --build $(XSI_BUILD_DIR) --config Release 57 | 58 | #-----------------------------------------------------------------------------# 59 | # cmake build targets 60 | #-----------------------------------------------------------------------------# 61 | 62 | install_maya:: 63 | cmake --install $(MAYA_BUILD_DIR) --config Release 64 | 65 | install_python:: 66 | cmake --install $(PYTHON_BUILD_DIR) --config Release 67 | 68 | install_xsi:: 69 | cmake --install $(XSI_BUILD_DIR) --config Release 70 | 71 | 72 | clean:: 73 | rm -rf $(MAYA_BUILD_DIR) 74 | rm -rf $(PYTHON_BUILD_DIR) 75 | rm -rf $(XSI_BUILD_DIR) 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Development for this repo has moved 2 | 3 | Development repositories for the c++ and python parts of Simplex have been combined, so this repository will no longer recieve updates. The main Simplex repo, however, is still under active use. 4 | 5 | https://github.com/blurstudio/Simplex 6 | 7 | -------------------------------------------------------------------------------- /mayaConfigure.bat: -------------------------------------------------------------------------------- 1 | setlocal 2 | 3 | SET MAYA_VERSION=2022 4 | SET BUILD=mayabuild_%MAYA_VERSION% 5 | SET COMPILER=Visual Studio 15 2017 Win64 6 | 7 | SET PFX=%~dp0 8 | cd %PFX% 9 | rmdir %BUILD% /s /q 10 | mkdir %BUILD% 11 | cd %BUILD% 12 | 13 | cmake ^ 14 | -DMAYA_VERSION=%MAYA_VERSION% ^ 15 | -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ^ 16 | -G "%COMPILER%" ..\ 17 | 18 | cmake --build . --config Release --target INSTALL 19 | 20 | pause 21 | -------------------------------------------------------------------------------- /modules/FindMaya.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2015 Chad Vernon 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | # - Maya finder module 24 | # 25 | # Variables that will be defined: 26 | # MAYA_FOUND Defined if a Maya installation has been detected 27 | # MAYA_EXECUTABLE Path to Maya's executable 28 | # MAYA__FOUND Defined if has been found 29 | # MAYA__LIBRARY Path to library 30 | # MAYA_INCLUDE_DIR Path to the devkit's include directories 31 | # MAYA_LIBRARIES All the Maya libraries 32 | # 33 | 34 | # Set a default Maya version if not specified 35 | if(NOT DEFINED MAYA_VERSION) 36 | set(MAYA_VERSION 2016 CACHE STRING "Maya version") 37 | endif() 38 | 39 | # OS Specific environment setup 40 | set(MAYA_COMPILE_DEFINITIONS "REQUIRE_IOSTREAM;_BOOL") 41 | set(MAYA_INSTALL_BASE_SUFFIX "") 42 | set(MAYA_INC_SUFFIX "include") 43 | set(MAYA_LIB_SUFFIX "lib") 44 | set(MAYA_BIN_SUFFIX "bin") 45 | set(MAYA_TARGET_TYPE LIBRARY) 46 | if(WIN32) 47 | # Windows 48 | set(MAYA_INSTALL_BASE_DEFAULT "C:/Program Files/Autodesk") 49 | set(MAYA_COMPILE_DEFINITIONS "${MAYA_COMPILE_DEFINITIONS};NT_PLUGIN") 50 | set(OPENMAYA OpenMaya.lib) 51 | set(MAYA_PLUGIN_EXTENSION ".mll") 52 | set(MAYA_TARGET_TYPE RUNTIME) 53 | elseif(APPLE) 54 | # Apple 55 | set(MAYA_INSTALL_BASE_DEFAULT /Applications/Autodesk) 56 | set(MAYA_INC_SUFFIX "devkit/include") 57 | set(MAYA_LIB_SUFFIX "Maya.app/Contents/MacOS") 58 | set(MAYA_BIN_SUFFIX "Maya.app/Contents/bin/") 59 | set(MAYA_COMPILE_DEFINITIONS "${MAYA_COMPILE_DEFINITIONS};OSMac_") 60 | set(OPENMAYA libOpenMaya.dylib) 61 | set(MAYA_PLUGIN_EXTENSION ".bundle") 62 | else() 63 | # Linux 64 | set(MAYA_COMPILE_DEFINITIONS "${MAYA_COMPILE_DEFINITIONS};LINUX") 65 | set(MAYA_INSTALL_BASE_DEFAULT /usr/autodesk) 66 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") 67 | if(MAYA_VERSION LESS 2016) 68 | SET(MAYA_INSTALL_BASE_SUFFIX -x64) 69 | endif() 70 | set(OPENMAYA libOpenMaya.so) 71 | set(MAYA_PLUGIN_EXTENSION ".so") 72 | endif() 73 | 74 | set(MAYA_INSTALL_BASE_PATH ${MAYA_INSTALL_BASE_DEFAULT} CACHE STRING 75 | "Root path containing your maya installations, e.g. /usr/autodesk or /Applications/Autodesk/") 76 | 77 | if(NOT DEFINED MAYA_LOCATION) 78 | if(WIN32) 79 | set(MAYA_LOCATION ${MAYA_INSTALL_BASE_PATH}/Maya${MAYA_VERSION}${MAYA_INSTALL_BASE_SUFFIX}) 80 | else() 81 | set(MAYA_LOCATION ${MAYA_INSTALL_BASE_PATH}/maya) 82 | endif() 83 | endif() 84 | 85 | # Maya library directory 86 | find_path(MAYA_LIBRARY_DIR ${OPENMAYA} 87 | PATHS 88 | ${MAYA_LOCATION} 89 | $ENV{MAYA_LOCATION} 90 | PATH_SUFFIXES 91 | "${MAYA_LIB_SUFFIX}/" 92 | DOC "Maya library path" 93 | ) 94 | 95 | # Maya include directory 96 | find_path(MAYA_INCLUDE_DIR maya/MFn.h 97 | PATHS 98 | ${MAYA_LOCATION} 99 | $ENV{MAYA_LOCATION} 100 | PATH_SUFFIXES 101 | "${MAYA_INC_SUFFIX}/" 102 | DOC "Maya include path" 103 | ) 104 | 105 | # Maya libraries 106 | set(_MAYA_LIBRARIES OpenMaya OpenMayaAnim OpenMayaFX OpenMayaRender OpenMayaUI Foundation clew) 107 | foreach(MAYA_LIB ${_MAYA_LIBRARIES}) 108 | find_library(MAYA_${MAYA_LIB}_LIBRARY NAMES ${MAYA_LIB} PATHS ${MAYA_LIBRARY_DIR} 109 | NO_DEFAULT_PATH) 110 | if (MAYA_${MAYA_LIB}_LIBRARY) 111 | set(MAYA_LIBRARIES ${MAYA_LIBRARIES} ${MAYA_${MAYA_LIB}_LIBRARY}) 112 | endif() 113 | endforeach() 114 | 115 | if (APPLE AND ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") 116 | # Clang and Maya needs to use libstdc++ 117 | set(MAYA_CXX_FLAGS "-std=c++0x -stdlib=libstdc++") 118 | endif() 119 | 120 | include(FindPackageHandleStandardArgs) 121 | find_package_handle_standard_args(Maya DEFAULT_MSG MAYA_INCLUDE_DIR MAYA_LIBRARIES) 122 | 123 | function(MAYA_PLUGIN _target) 124 | if (WIN32) 125 | set_target_properties(${_target} PROPERTIES 126 | LINK_FLAGS "/export:initializePlugin /export:uninitializePlugin" 127 | ) 128 | endif() 129 | set_target_properties(${_target} PROPERTIES 130 | COMPILE_DEFINITIONS "${MAYA_COMPILE_DEFINITIONS}" 131 | PREFIX "" 132 | SUFFIX ${MAYA_PLUGIN_EXTENSION}) 133 | endfunction() 134 | -------------------------------------------------------------------------------- /pythonConfigure.bat: -------------------------------------------------------------------------------- 1 | setlocal 2 | 3 | SET BUILD=pybuild 4 | SET PY_VERSION=37 5 | SET ARCH=64 6 | SET COMPILER=Visual Studio 16 2019 7 | 8 | SET PFX=%~dp0 9 | cd %PFX% 10 | rmdir %BUILD% /s /q 11 | mkdir %BUILD% 12 | cd %BUILD% 13 | 14 | 15 | if "%ARCH%" == "64" ( 16 | set PY_VERSION=%PY_VERSION%_64 17 | if "%COMPILER%" NEQ "Visual Studio 16 2019" ( 18 | SET COMPILER=%COMPILER% Win64 19 | ) 20 | ) 21 | 22 | cmake ^ 23 | -DTARGET_DCC=Python3 ^ 24 | -DPY_VERSION=%PY_VERSION% ^ 25 | -G "%COMPILER%" ..\ 26 | 27 | cmake --build . --config Release --target INSTALL 28 | 29 | pause 30 | 31 | -------------------------------------------------------------------------------- /src/lib/combo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #include "enums.h" 21 | #include "utils.h" 22 | #include "shapeController.h" 23 | #include "slider.h" 24 | #include "combo.h" 25 | #include "floater.h" 26 | #include "simplex.h" 27 | 28 | #include "rapidjson/rapidjson.h" 29 | #include "math.h" 30 | 31 | #include // for sort 32 | #include // for numeric_limits 33 | 34 | using namespace simplex; 35 | class simplex::Progression; 36 | 37 | 38 | bool simplex::solveState(const std::vector &vals, const std::vector &tars, ComboSolve solveType, bool exact, double &value) { 39 | double mn, mx, allMul = 1.0, allSum = 0.0; 40 | mn = std::numeric_limits::infinity(); 41 | mx = -mn; 42 | 43 | for (size_t i = 0; i < vals.size(); ++i){ 44 | double val = vals[i]; 45 | double tar = tars[i]; 46 | 47 | // Specifically this instead of isNegative() 48 | // because isNegative returns true for 0.0 49 | bool valNeg = !isPositive(val); 50 | bool tarNeg = !isPositive(tar); 51 | 52 | if (valNeg != tarNeg) return false; 53 | if (valNeg) val = -val; 54 | 55 | val = (val > MAXVAL) ? MAXVAL : val; 56 | allMul *= val; 57 | allSum += val; 58 | if (val < mn) mn = val; 59 | if (val > mx) mx = val; 60 | } 61 | 62 | switch (solveType) { 63 | case ComboSolve::min: 64 | value = (exact) ? mn : doSoftMin(mx, mn); 65 | break; 66 | case ComboSolve::allMul: 67 | value = allMul; 68 | break; 69 | case ComboSolve::extMul: 70 | value = mx * mn; 71 | break; 72 | case ComboSolve::mulAvgExt: 73 | if (isZero(mx + mn)) 74 | value = 0.0; 75 | else 76 | value = 2 * (mx * mn) / (mx + mn); 77 | break; 78 | case ComboSolve::mulAvgAll: 79 | if (isZero(allSum)) 80 | value = 0.0; 81 | else 82 | value = vals.size() * allMul / allSum; 83 | break; 84 | case ComboSolve::None: 85 | value = (exact) ? mn : doSoftMin(mx, mn); 86 | break; 87 | default: 88 | value = (exact) ? mn : doSoftMin(mx, mn); 89 | } 90 | return true; 91 | } 92 | 93 | bool simplex::solveState(const ComboPairs &stateList, ComboSolve solveType, bool exact, double &value) { 94 | std::vector vals, tars; 95 | for (auto sit = stateList.begin(); sit != stateList.end(); ++sit) { 96 | //for (const auto &state: stateList){ 97 | const auto &state = *sit; 98 | vals.push_back(state.first->getValue()); 99 | tars.push_back(state.second); 100 | } 101 | return simplex::solveState(vals, tars, solveType, exact, value); 102 | } 103 | 104 | ComboSolve simplex::getSolveType(const rapidjson::Value &val) { 105 | ComboSolve solveType = ComboSolve::None; 106 | auto solveIt = val.FindMember("solveType"); 107 | if (solveIt != val.MemberEnd()) { 108 | if (!solveIt->value.IsString()) { 109 | solveType = ComboSolve::None; 110 | } 111 | else { 112 | std::string solve(solveIt->value.GetString()); 113 | if (solve == "min") 114 | solveType = ComboSolve::min; 115 | else if (solve == "allMul") 116 | solveType = ComboSolve::allMul; 117 | else if (solve == "extMul") 118 | solveType = ComboSolve::extMul; 119 | else if (solve == "mulAvgExt") 120 | solveType = ComboSolve::mulAvgExt; 121 | else if (solve == "mulAvgAll") 122 | solveType = ComboSolve::mulAvgAll; 123 | else if (solve == "None") 124 | solveType = ComboSolve::None; 125 | else 126 | solveType = ComboSolve::None; 127 | } 128 | } 129 | return solveType; 130 | } 131 | 132 | bool simplex::getSolvePairs(const rapidjson::Value &val, Simplex *simp, ComboPairs &state, bool &isFloater) { 133 | for (auto it = val.Begin(); it != val.End(); ++it) { 134 | auto &ival = *it; 135 | if (!ival.IsArray()) return false; 136 | if (!ival[0].IsInt()) return false; 137 | if (!ival[1].IsDouble()) return false; 138 | 139 | size_t slidx = (size_t)ival[0].GetInt(); 140 | double slval = (double)ival[1].GetDouble(); 141 | if (!floatEQ(fabs(slval), 1.0, EPS) && !isZero(slval)) 142 | isFloater = true; 143 | if (slidx >= simp->sliders.size()) return false; 144 | state.push_back(std::make_pair(&simp->sliders[slidx], slval)); 145 | } 146 | return true; 147 | } 148 | 149 | Combo::Combo(const std::string &name, Progression* prog, size_t index, 150 | const ComboPairs &stateList, bool isFloater, ComboSolve solveType) : 151 | ShapeController(name, prog, index), stateList(stateList), isFloater(isFloater), solveType(solveType), exact(true) { 152 | std::sort(this->stateList.begin(), this->stateList.end(), 153 | [](const ComboPair &lhs, const ComboPair &rhs) { 154 | return lhs.first->getIndex() < rhs.first->getIndex(); 155 | } 156 | ); 157 | std::vector rawVec; 158 | for (auto pit = this->stateList.begin(); pit != this->stateList.end(); ++pit) { 159 | //for (auto &p : this->stateList) { 160 | auto &p = *pit; 161 | rawVec.push_back(p.second); 162 | } 163 | rectify(rawVec, rectified, clamped, inverted); 164 | } 165 | 166 | void Combo::storeValue( 167 | const std::vector &values, 168 | const std::vector &posValues, 169 | const std::vector &clamped, 170 | const std::vector &inverses) { 171 | 172 | if (!enabled) return; 173 | if (isFloater) return; 174 | solveState(stateList, solveType, exact, value); 175 | } 176 | 177 | bool Combo::parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp) { 178 | if (!val[0u].IsString()) return false; 179 | if (!val[1].IsInt()) return false; 180 | const rapidjson::Value &jcstate = val[2]; 181 | ComboPairs state; 182 | 183 | bool isFloater = false; 184 | rapidjson::SizeType j; 185 | for (j = 0; j < jcstate.Size(); ++j) { 186 | if (!jcstate[j][0u].IsInt()) return false; 187 | if (!jcstate[j][1].IsNumber()) return false; 188 | size_t slidx = (size_t)jcstate[j][0u].GetInt(); 189 | double slval = jcstate[j][1].GetDouble(); 190 | 191 | if (!floatEQ(fabs(slval), 1.0, EPS) && !isZero(slval)) 192 | isFloater = true; 193 | 194 | if (slidx >= simp->sliders.size()) return false; 195 | state.push_back(std::make_pair(&simp->sliders[slidx], slval)); 196 | } 197 | 198 | std::string name(val[0u].GetString()); 199 | size_t pidx = (size_t)val[1].GetInt(); 200 | if (pidx >= simp->progs.size()) return false; 201 | if (isFloater) 202 | simp->floaters.push_back(Floater(name, &simp->progs[pidx], index, state, isFloater)); 203 | simp->combos.push_back(Combo(name, &simp->progs[pidx], index, state, isFloater, ComboSolve::None)); 204 | return true; 205 | } 206 | 207 | bool Combo::parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp) { 208 | if (!val.IsObject()) return false; 209 | CHECK_JSON_STRING(nameIt, "name", val); 210 | CHECK_JSON_INT(progIt, "prog", val); 211 | CHECK_JSON_ARRAY(pairsIt, "pairs", val); 212 | 213 | std::string name(nameIt->value.GetString()); 214 | 215 | ComboSolve solveType = getSolveType(val); 216 | ComboPairs state; 217 | bool isFloater = false; 218 | auto &pairsVal = pairsIt->value; 219 | if (!getSolvePairs(pairsVal, simp, state, isFloater)) return false; 220 | 221 | size_t pidx = (size_t)progIt->value.GetInt(); 222 | if (pidx >= simp->progs.size()) return false; 223 | 224 | bool enabled = getEnabled(val); 225 | 226 | if (isFloater) { 227 | simp->floaters.push_back(Floater(name, &simp->progs[pidx], index, state, isFloater)); 228 | simp->floaters.back().setEnabled(enabled); 229 | } 230 | // because a floater is still considered a combo 231 | // I need to add it to the list for indexing purposes 232 | 233 | simp->combos.push_back(Combo(name, &simp->progs[pidx], index, state, isFloater, solveType)); 234 | simp->combos.back().setEnabled(enabled); 235 | return true; 236 | } 237 | 238 | bool Combo::parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp) { 239 | return parseJSONv2(val, index, simp); 240 | } 241 | 242 | -------------------------------------------------------------------------------- /src/lib/combo.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "enums.h" 23 | #include "shapeController.h" 24 | #include "rapidjson/document.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace simplex { 31 | 32 | class Progression; 33 | class Slider; 34 | class Simplex; 35 | 36 | typedef std::pair ComboPair; 37 | typedef std::vector ComboPairs; 38 | 39 | ComboSolve getSolveType(const rapidjson::Value &val); 40 | bool getSolvePairs(const rapidjson::Value &val, Simplex *simp, ComboPairs &state, bool &isFloater); 41 | 42 | bool solveState(const std::vector &vals, const std::vector &tars, ComboSolve solveType, bool exact, double &value); 43 | bool solveState(const ComboPairs &stateList, ComboSolve solveType, bool exact, double &value); 44 | 45 | class Combo : public ShapeController { 46 | private: 47 | bool isFloater; 48 | bool exact; 49 | ComboSolve solveType; 50 | protected: 51 | std::vector inverted; 52 | std::vector rectified; 53 | std::vector clamped; 54 | public: 55 | ComboPairs stateList; 56 | bool sliderType() const override { return false; } 57 | void setExact(bool e){exact = e;} 58 | Combo(const std::string &name, Progression* prog, size_t index, 59 | const ComboPairs &stateList, bool isFloater, ComboSolve solveType); 60 | void storeValue( 61 | const std::vector &values, 62 | const std::vector &posValues, 63 | const std::vector &clamped, 64 | const std::vector &inverses); 65 | static bool parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp); 66 | static bool parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp); 67 | static bool parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp); 68 | }; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/lib/enums.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | #pragma once 20 | 21 | namespace simplex { 22 | 23 | enum ProgType {linear, spline, splitSpline}; 24 | enum ComboSolve {min, allMul, extMul, mulAvgAll, mulAvgExt, None}; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/lib/floater.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "enums.h" 23 | #include "combo.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace simplex { 30 | 31 | class Slider; 32 | class Floater : public Combo { 33 | public: 34 | friend class TriSpace; // lets the trispace set the value for this guy 35 | Floater(const std::string &name, Progression* prog, size_t index, 36 | const std::vector> &stateList, bool isFloater) : 37 | Combo(name, prog, index, stateList, isFloater, ComboSolve::None) { 38 | } 39 | }; 40 | 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/lib/progression.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #include "shapeBase.h" 21 | #include "progression.h" 22 | #include "simplex.h" 23 | #include "enums.h" 24 | 25 | #include "rapidjson/document.h" 26 | #include "rapidjson/rapidjson.h" 27 | 28 | #include // for sort 29 | #include 30 | #include 31 | #include 32 | 33 | using namespace simplex; 34 | class simplex::Shape; 35 | 36 | Progression::Progression(const std::string &name, const ProgPairs &pairs, ProgType interp): 37 | ShapeBase(name), pairs(pairs), interp(interp) { 38 | std::sort(this->pairs.begin(), this->pairs.end(), 39 | [](const ProgPair &a, const ProgPair &b) { 40 | return a.second < b.second; 41 | } 42 | ); 43 | } 44 | 45 | size_t Progression::getInterval(double tVal, const std::vector ×, bool &outside){ 46 | if (times.size() <= 1){ 47 | outside = true; 48 | return 0; 49 | } 50 | outside = tVal < times[0] || tVal > times[times.size() - 1]; 51 | if (tVal >= times[times.size() - 2]){ 52 | return times.size() - 2; 53 | } 54 | else if (tVal < times[0]){ 55 | return 0; 56 | } 57 | else{ 58 | // the percent for the current segment of tVal 59 | // and the corresponding basis values 60 | for (size_t i=0; i sided; 71 | for (size_t i = 0; i < pairs.size(); ++i) { 72 | sided.push_back(&(pairs[i])); 73 | } 74 | return getRawSplineOutput(sided, tVal, mul); 75 | } 76 | 77 | ProgPairs Progression::getSplitSplineOutput(double tVal, double mul) const{ 78 | std::vector sided; 79 | bool gt = tVal >= 0.0; 80 | for (size_t i = 0; i < pairs.size(); ++i) { 81 | if (gt && pairs[i].second >= 0) 82 | sided.push_back(&(pairs[i])); 83 | else if (!gt && pairs[i].second <= 0) 84 | sided.push_back(&(pairs[i])); 85 | } 86 | return getRawSplineOutput(sided, tVal, mul); 87 | } 88 | 89 | ProgPairs Progression::getLinearOutput(double tVal, double mul) const{ 90 | std::vector sided; 91 | for (size_t i = 0; i < pairs.size(); ++i) { 92 | sided.push_back(&(pairs[i])); 93 | } 94 | return getRawLinearOutput(sided, tVal, mul); 95 | } 96 | 97 | ProgPairs Progression::getRawSplineOutput(const std::vector* > pairs, double tVal, double mul){ 98 | if ( 99 | (pairs.size() <= 2) || 100 | (tVal < pairs[0]->second) && (tVal > pairs[pairs.size()-1]->second) 101 | ){ 102 | return getRawLinearOutput(pairs, tVal, mul); 103 | } 104 | 105 | std::vector shapes; 106 | std::vector st; 107 | for (auto it = pairs.begin(); it != pairs.end(); ++it){ 108 | shapes.push_back((*it)->first); 109 | st.push_back((*it)->second); 110 | } 111 | bool outside = false; 112 | size_t interval = getInterval(tVal, st, outside); 113 | ProgPairs out; 114 | 115 | double start = st[interval]; 116 | double end = st[interval + 1]; 117 | 118 | //# compute the catmull-rom basis multipliers 119 | double x = (tVal - start) / (end - start); 120 | if (outside) { 121 | // If I'm outside the range of the spline, then I linear interpolate along the implicit tangent 122 | if (interval == 0) { 123 | out.push_back(std::make_pair(shapes[0], mul * (1.0 - x))); 124 | out.push_back(std::make_pair(shapes[1], mul * x)); 125 | } 126 | else { 127 | out.push_back(std::make_pair(shapes[shapes.size() - 1], mul * x)); 128 | out.push_back(std::make_pair(shapes[shapes.size() - 2], mul * (1.0 - x))); 129 | } 130 | } 131 | else{ 132 | double x2 = x*x; 133 | double x3 = x2*x; 134 | double v0 = (-0.5*x3 + 1.0*x2 - 0.5*x); 135 | double v1 = (1.5*x3 - 2.5*x2 + 1.0); 136 | double v2 = (-1.5*x3 + 2.0*x2 + 0.5*x); 137 | double v3 = (0.5*x3 - 0.5*x2); 138 | if (interval == 0) { // deal with input tangent 139 | out.push_back(std::make_pair(shapes[0], mul * (v1 + v0 + v0))); 140 | out.push_back(std::make_pair(shapes[1], mul * (v2 - v0))); 141 | out.push_back(std::make_pair(shapes[2], mul * (v3))); 142 | } 143 | else if (interval == st.size() - 2) { // deal with output tangent 144 | out.push_back(std::make_pair(shapes[shapes.size() - 3], mul * (v0))); 145 | out.push_back(std::make_pair(shapes[shapes.size() - 2], mul * (v1 - v3))); 146 | out.push_back(std::make_pair(shapes[shapes.size() - 1], mul * (v2 + v3 + v3))); 147 | } 148 | else { 149 | out.push_back(std::make_pair(shapes[interval - 1], mul * v0)); 150 | out.push_back(std::make_pair(shapes[interval + 0], mul * v1)); 151 | out.push_back(std::make_pair(shapes[interval + 1], mul * v2)); 152 | out.push_back(std::make_pair(shapes[interval + 2], mul * v3)); 153 | } 154 | } 155 | return out; 156 | } 157 | 158 | ProgPairs Progression::getRawLinearOutput(const std::vector* > pairs, double tVal, double mul){ 159 | ProgPairs out; 160 | std::vector times; 161 | if (pairs.size() < 2) return out; 162 | 163 | for (auto it=pairs.begin(); it!=pairs.end(); ++it){ 164 | times.push_back((*it)->second); 165 | } 166 | bool outside; 167 | size_t idx = getInterval(tVal, times, outside); 168 | double u = (tVal - times[idx]) / (times[idx+1] - times[idx]); 169 | out.push_back(std::make_pair(pairs[idx]->first, mul * (1.0-u))); 170 | out.push_back(std::make_pair(pairs[idx+1]->first, mul * u)); 171 | return out; 172 | } 173 | 174 | ProgPairs Progression::getOutput(double tVal, double mul) const{ 175 | if (interp == ProgType::spline) 176 | return getSplineOutput(tVal, mul); 177 | else if (interp == ProgType::splitSpline) 178 | return getSplitSplineOutput(tVal, mul); 179 | else // if (interp == ProgType::linear) 180 | return getLinearOutput(tVal, mul); 181 | } 182 | 183 | bool Progression::parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp){ 184 | if (!val.IsArray()) return false; 185 | 186 | ProgPairs pairs; 187 | const rapidjson::Value &jindices = val[1]; 188 | const rapidjson::Value &jweights = val[2]; 189 | if (!jweights.IsArray() || !jindices.IsArray()) return false; 190 | 191 | rapidjson::SizeType j; 192 | for (j = 0; j= simp->shapes.size()) return false; 198 | pairs.push_back(std::make_pair(&simp->shapes[x], y)); 199 | } 200 | 201 | if (!val[0u].IsString()) return false; 202 | std::string name(val[0u].GetString()); 203 | 204 | ProgType interp = ProgType::spline; 205 | 206 | if (val.Size() > 3){ 207 | if (!val[3].IsString()) return false; 208 | std::string interpStr = val[3].GetString(); 209 | if (interpStr == "linear") { 210 | interp = ProgType::linear; 211 | } 212 | } 213 | simp->progs.push_back(Progression(name, pairs, interp)); 214 | return true; 215 | } 216 | 217 | bool Progression::parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp){ 218 | if (!val.IsObject()) return false; 219 | 220 | CHECK_JSON_STRING(nameIt, "name", val); 221 | CHECK_JSON_ARRAY(pairsIt, "pairs", val); 222 | CHECK_JSON_STRING(interpIt, "interp", val); 223 | 224 | std::string name(nameIt->value.GetString()); 225 | 226 | std::string interpStr(interpIt->value.GetString()); 227 | ProgType interp = ProgType::spline; 228 | if (interpStr == "linear") 229 | interp = ProgType::linear; 230 | else if (interpStr == "splitspline") 231 | interp = ProgType::splitSpline; 232 | 233 | ProgPairs pairs; 234 | 235 | auto &pairsVal = pairsIt->value; 236 | for (auto it = pairsVal.Begin(); it != pairsVal.End(); ++it){ 237 | auto &ival = *it; 238 | if (!ival.IsArray()) return false; 239 | if (!ival[0].IsInt()) return false; 240 | if (!ival[1].IsDouble()) return false; 241 | 242 | size_t x = (size_t)ival[0].GetInt(); 243 | double y = (double)ival[1].GetDouble(); 244 | 245 | if (x >= simp->shapes.size()) return false; 246 | pairs.push_back(std::make_pair(&simp->shapes[x], y)); 247 | } 248 | simp->progs.push_back(Progression(name, pairs, interp)); 249 | return true; 250 | } 251 | 252 | bool Progression::parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp){ 253 | return parseJSONv2(val, index, simp); 254 | } 255 | 256 | 257 | -------------------------------------------------------------------------------- /src/lib/progression.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "enums.h" 23 | #include "shapeBase.h" 24 | #include "rapidjson/document.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | namespace simplex { 32 | 33 | class Simplex; 34 | class Shape; 35 | 36 | typedef std::pair ProgPair; 37 | typedef std::vector ProgPairs; 38 | 39 | class Progression : public ShapeBase { 40 | private: 41 | ProgPairs pairs; 42 | ProgType interp; 43 | static size_t getInterval(double tVal, const std::vector ×, bool &outside); 44 | ProgPairs getSplineOutput(double tVal, double mul=1.0) const; 45 | ProgPairs getSplitSplineOutput(double tVal, double mul=1.0) const; 46 | ProgPairs getLinearOutput(double tVal, double mul=1.0) const; 47 | 48 | static ProgPairs getRawSplineOutput(const std::vector* > pairs, double tVal, double mul=1.0); 49 | static ProgPairs getRawLinearOutput(const std::vector* > pairs, double tVal, double mul=1.0); 50 | 51 | public: 52 | ProgPairs getOutput(double tVal, double mul=1.0) const; 53 | 54 | Progression(const std::string &name, const ProgPairs &pairs, ProgType interp); 55 | static bool parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp); 56 | static bool parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp); 57 | static bool parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp); 58 | }; 59 | 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/lib/shape.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | #include "simplex.h" 20 | #include "shape.h" 21 | 22 | #include "rapidjson/document.h" 23 | 24 | #include 25 | #include 26 | 27 | using namespace simplex; 28 | 29 | bool Shape::parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp){ 30 | if(!val.IsString()) return false; 31 | std::string name(val.GetString()); 32 | simp->shapes.push_back(Shape(name, index)); 33 | return true; 34 | } 35 | 36 | bool Shape::parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp){ 37 | if (!val.IsObject()) return false; 38 | 39 | CHECK_JSON_STRING(nameIt, "name", val); 40 | 41 | std::string name(nameIt->value.GetString()); 42 | simp->shapes.push_back(Shape(name, index)); 43 | return true; 44 | } 45 | 46 | bool Shape::parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp){ 47 | return parseJSONv2(val, index, simp); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/lib/shape.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "shapeBase.h" 23 | #include "rapidjson/document.h" 24 | #include 25 | 26 | namespace simplex { 27 | 28 | class Simplex; 29 | 30 | class Shape : public ShapeBase { 31 | public: 32 | Shape(const std::string &name, size_t index): ShapeBase(name, index){} 33 | static bool parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp); 34 | static bool parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp); 35 | static bool parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp); 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/lib/shapeBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "enums.h" 23 | #include 24 | 25 | namespace simplex { 26 | 27 | class ShapeBase { 28 | protected: 29 | void *shapeRef; // pointer to whatever the user wants 30 | std::string name; 31 | size_t index; 32 | public: 33 | explicit ShapeBase(const std::string &name, size_t index): name(name), index(index), shapeRef(nullptr) {} 34 | explicit ShapeBase(const std::string &name): name(name), index(0u), shapeRef(nullptr) {} 35 | const std::string* getName() const {return &name;} 36 | const size_t getIndex() const { return index; } 37 | void setUserData(void *data) {shapeRef = data;} 38 | void* getUserData(){return shapeRef;} 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/lib/shapeController.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | #include "simplex.h" 20 | #include "shapeController.h" 21 | #include "progression.h" 22 | #include "shape.h" 23 | 24 | #include 25 | #include 26 | #include "math.h" 27 | 28 | using namespace simplex; 29 | 30 | void ShapeController::solve(std::vector &accumulator, double &maxAct) const { 31 | double vm = fabs(value * multiplier); 32 | if (vm > maxAct) maxAct = vm; 33 | 34 | ProgPairs shapeVals = prog->getOutput(value, multiplier); 35 | for (auto sit=shapeVals.begin(); sit!=shapeVals.end(); ++sit){ 36 | //for (const auto &svp: shapeVals){ 37 | const auto &svp = *sit; 38 | accumulator[svp.first->getIndex()] += svp.second; 39 | } 40 | } 41 | 42 | bool ShapeController::getEnabled(const rapidjson::Value &val) { 43 | auto enIt = val.FindMember("enabled"); 44 | if (enIt != val.MemberEnd()) { 45 | if (enIt->value.IsBool()) { 46 | return enIt->value.GetBool(); 47 | } 48 | } 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /src/lib/shapeController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "shapeBase.h" 23 | #include "rapidjson/document.h" 24 | 25 | #include 26 | #include 27 | 28 | namespace simplex { 29 | 30 | class Progression; 31 | 32 | class ShapeController : public ShapeBase { 33 | protected: 34 | bool enabled; 35 | double value; 36 | double multiplier; 37 | Progression* prog; 38 | public: 39 | ShapeController(const std::string &name, Progression* prog, size_t index): 40 | ShapeBase(name, index), enabled(true), value(0.0), multiplier(1.0), prog(prog) {} 41 | 42 | virtual bool sliderType() const { return true; } 43 | void clearValue(){value = 0.0; multiplier=1.0;} 44 | const double getValue() const { return value; } 45 | const double getMultiplier() const { return multiplier; } 46 | void setEnabled(bool enable){enabled = enable;} 47 | virtual void storeValue( 48 | const std::vector &values, 49 | const std::vector &posValues, 50 | const std::vector &clamped, 51 | const std::vector &inverses) = 0; 52 | void solve(std::vector &accumulator, double &maxAct) const; 53 | static bool getEnabled(const rapidjson::Value &val); 54 | }; 55 | 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/lib/simplex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | #include "utils.h" 20 | #include "simplex.h" 21 | 22 | #include "rapidjson/error/en.h" 23 | #include "rapidjson/rapidjson.h" 24 | 25 | using namespace simplex; 26 | 27 | void Simplex::clearValues(){ 28 | for (auto xit = sliders.begin(); xit != sliders.end(); ++xit) { xit->clearValue(); } 29 | for (auto xit = combos.begin(); xit != combos.end(); ++xit) { xit->clearValue(); } 30 | for (auto xit = floaters.begin(); xit != floaters.end(); ++xit) { xit->clearValue(); } 31 | for (auto xit = traversals.begin(); xit != traversals.end(); ++xit) { xit->clearValue(); } 32 | 33 | //for (auto &x : sliders) x.clearValue(); 34 | //for (auto &x : combos) x.clearValue(); 35 | //for (auto &x : floaters) x.clearValue(); 36 | //for (auto &x : traversals) x.clearValue(); 37 | } 38 | 39 | void Simplex::setExactSolve(bool exact){ 40 | for (auto xit = combos.begin(); xit != combos.end(); ++xit) { xit->setExact(exact); } 41 | //for (auto &x : combos) x.setExact(exact); 42 | } 43 | 44 | std::vector Simplex::solve(const std::vector &vec){ 45 | // The solver should simply follow this pattern: 46 | // Ask each top level thing to store its value 47 | // Ask each shape controller for its contribution to the output 48 | std::vector posVec, clamped, output; 49 | std::vector inverses; 50 | rectify(vec, posVec, clamped, inverses); 51 | 52 | 53 | for (auto xit = sliders.begin(); xit != sliders.end(); ++xit){ 54 | xit->storeValue(vec, posVec, clamped, inverses); 55 | } 56 | for (auto xit = combos.begin(); xit != combos.end(); ++xit){ 57 | xit->storeValue(vec, posVec, clamped, inverses); 58 | } 59 | for (auto xit = spaces.begin(); xit != spaces.end(); ++xit){ 60 | xit->storeValue(vec, posVec, clamped, inverses); 61 | } 62 | for (auto xit = traversals.begin(); xit != traversals.end(); ++xit){ 63 | xit->storeValue(vec, posVec, clamped, inverses); 64 | } 65 | 66 | /* 67 | for (auto &x : sliders) 68 | x.storeValue(vec, posVec, clamped, inverses); 69 | for (auto &x : combos) 70 | x.storeValue(vec, posVec, clamped, inverses); 71 | for (auto &x : spaces) 72 | x.storeValue(vec, posVec, clamped, inverses); 73 | for (auto &x : traversals) 74 | x.storeValue(vec, posVec, clamped, inverses); 75 | */ 76 | 77 | output.resize(shapes.size()); 78 | double maxAct = 0.0; 79 | 80 | for (auto xit = sliders.begin(); xit != sliders.end(); ++xit) 81 | xit->solve(output, maxAct); 82 | for (auto xit = combos.begin(); xit != combos.end(); ++xit) 83 | xit->solve(output, maxAct); 84 | for (auto xit = floaters.begin(); xit != floaters.end(); ++xit) 85 | xit->solve(output, maxAct); 86 | for (auto xit = traversals.begin(); xit != traversals.end(); ++xit) 87 | xit->solve(output, maxAct); 88 | 89 | /* 90 | for (auto &x : sliders) 91 | x.solve(output, maxAct); 92 | for (auto &x : combos) 93 | x.solve(output, maxAct); 94 | for (auto &x : floaters) 95 | x.solve(output, maxAct); 96 | for (auto &x : traversals) 97 | x.solve(output, maxAct); 98 | */ 99 | 100 | // set the rest value properly 101 | if (!output.empty()) 102 | output[0] = 1.0 - maxAct; 103 | return output; 104 | } 105 | 106 | Simplex::Simplex(const std::string &json){ 107 | parseJSON(json); 108 | } 109 | 110 | Simplex::Simplex(const char *json){ 111 | parseJSON(std::string(json)); 112 | } 113 | 114 | bool Simplex::parseJSONversion(const rapidjson::Document &d, unsigned version){ 115 | // Must have these 116 | if (!d.HasMember("shapes")) return false; 117 | if (!d.HasMember("progressions")) return false; 118 | if (!d.HasMember("sliders")) return false; 119 | 120 | const rapidjson::Value &jshapes = d["shapes"]; 121 | const rapidjson::Value &jsliders = d["sliders"]; 122 | const rapidjson::Value &jprogs = d["progressions"]; 123 | 124 | if (!jshapes.IsArray()) return false; 125 | if (!jsliders.IsArray()) return false; 126 | if (!jprogs.IsArray()) return false; 127 | 128 | rapidjson::SizeType i; 129 | bool ret; 130 | for (i = 0; i(json.c_str()); 205 | 206 | hasParseError = false; 207 | if (d.HasParseError()){ 208 | hasParseError = true; 209 | parseError = std::string(rapidjson::GetParseError_En(d.GetParseError())); 210 | parseErrorOffset = d.GetErrorOffset(); 211 | return false; 212 | } 213 | 214 | unsigned encoding = 1u; 215 | if (d.HasMember("encodingVersion")){ 216 | const rapidjson::Value &ev = d["encodingVersion"]; 217 | if (!ev.IsUint()) return false; 218 | encoding = ev.GetUint(); 219 | } 220 | return parseJSONversion(d, encoding); 221 | } 222 | 223 | void Simplex::clear() { 224 | shapes.clear(); 225 | progs.clear(); 226 | sliders.clear(); 227 | combos.clear(); 228 | floaters.clear(); 229 | spaces.clear(); 230 | traversals.clear(); 231 | 232 | built = false; 233 | loaded = false; 234 | hasParseError = false; 235 | } 236 | 237 | void Simplex::build() { 238 | spaces = TriSpace::buildSpaces(floaters); 239 | built = true; 240 | } 241 | 242 | -------------------------------------------------------------------------------- /src/lib/simplex.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "shape.h" 23 | #include "progression.h" 24 | #include "slider.h" 25 | #include "combo.h" 26 | #include "floater.h" 27 | #include "trispace.h" 28 | #include "traversal.h" 29 | 30 | #include "rapidjson/document.h" 31 | 32 | #include 33 | #include 34 | 35 | namespace simplex { 36 | 37 | class Simplex { 38 | private: 39 | bool exactSolve; 40 | public: 41 | std::vector shapes; 42 | std::vector progs; 43 | std::vector sliders; 44 | std::vector combos; 45 | std::vector floaters; 46 | std::vector spaces; 47 | std::vector traversals; 48 | 49 | bool built; 50 | bool loaded; 51 | bool hasParseError; 52 | 53 | std::string parseError; 54 | size_t parseErrorOffset; 55 | const size_t sliderLen() const { return sliders.size(); } 56 | 57 | Simplex():exactSolve(true), built(false), loaded(false), hasParseError(false) {}; 58 | explicit Simplex(const std::string &json); 59 | explicit Simplex(const char* json); 60 | 61 | void clearValues(); 62 | void clear(); 63 | bool parseJSON(const std::string &json); 64 | bool parseJSONversion(const rapidjson::Document &d, unsigned version); 65 | void build(); 66 | 67 | void setExactSolve(bool exact); 68 | bool getExactSolve() { return exactSolve; } 69 | 70 | std::vector solve(const std::vector &vec); 71 | }; 72 | 73 | } // end namespace simplex 74 | -------------------------------------------------------------------------------- /src/lib/slider.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | #include "simplex.h" 20 | #include "slider.h" 21 | 22 | #include "rapidjson/document.h" 23 | 24 | #include 25 | #include 26 | 27 | using namespace simplex; 28 | 29 | bool Slider::parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp){ 30 | if (!val[0u].IsString()) return false; 31 | if (!val[1].IsInt()) return false; 32 | 33 | std::string name(val[0u].GetString()); // needs to be 0u 34 | size_t slidx = size_t(val[1].GetInt()); 35 | 36 | if (slidx >= simp->progs.size()) return false; 37 | simp->sliders.push_back(Slider(name, &simp->progs[slidx], index)); 38 | return true; 39 | } 40 | 41 | bool Slider::parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp){ 42 | if (!val.IsObject()) return false; 43 | 44 | CHECK_JSON_STRING(nameIt, "name", val); 45 | CHECK_JSON_INT(progIt, "prog", val); 46 | 47 | std::string name(nameIt->value.GetString()); 48 | size_t slidx = size_t(progIt->value.GetInt()); 49 | 50 | if (slidx >= simp->progs.size()) return false; 51 | 52 | bool enabled = getEnabled(val); 53 | 54 | simp->sliders.push_back(Slider(name, &simp->progs[slidx], index)); 55 | simp->sliders.back().setEnabled(enabled); 56 | return true; 57 | } 58 | 59 | bool Slider::parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp){ 60 | return parseJSONv2(val, index, simp); 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/lib/slider.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "shapeController.h" 23 | #include "rapidjson/document.h" 24 | 25 | #include 26 | #include 27 | 28 | namespace simplex { 29 | 30 | class Simplex; 31 | class Progression; 32 | 33 | class Slider : public ShapeController { 34 | public: 35 | Slider(const std::string &name, Progression* prog, size_t index) : ShapeController(name, prog, index){} 36 | void storeValue( 37 | const std::vector &values, 38 | const std::vector &posValues, 39 | const std::vector &clamped, 40 | const std::vector &inverses){ 41 | if (!enabled) return; 42 | this->value = values[this->index]; 43 | } 44 | 45 | static bool parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp); 46 | static bool parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp); 47 | static bool parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp); 48 | }; 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/lib/traversal.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | #include "shapeController.h" 20 | #include "slider.h" 21 | #include "combo.h" 22 | #include "traversal.h" 23 | #include "simplex.h" 24 | 25 | #include "rapidjson/document.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | using namespace simplex; 33 | 34 | Traversal::Traversal( 35 | const std::string &name, Progression* prog, size_t index, 36 | ShapeController* progressCtrl, ShapeController* multiplierCtrl, bool valueFlip, bool multiplierFlip): 37 | ShapeController(name, prog, index), exact(true){ 38 | 39 | if (multiplierCtrl->sliderType()) { 40 | multState.push_back(std::make_pair((Slider*)multiplierCtrl, multiplierFlip ? -1.0 : 1.0)); 41 | } 42 | else { 43 | // loop over the combos. Also, multiplier flip should *never* be negative here 44 | Combo *cmb = (Combo *) multiplierCtrl; 45 | for (auto pairIt = cmb->stateList.begin(); pairIt != cmb->stateList.end(); ++pairIt){ 46 | multState.push_back(std::make_pair(pairIt->first, pairIt->second)); 47 | } 48 | } 49 | 50 | if (progressCtrl->sliderType()) { 51 | progStartState.push_back(std::make_pair((Slider*)progressCtrl, 0.0)); 52 | progDeltaState.push_back(std::make_pair((Slider*)progressCtrl, valueFlip ? -1.0 : 1.0)); 53 | } 54 | else { 55 | // loop over the combos. Also, multiplier flip should *never* be negative here 56 | Combo *cmb = (Combo *) progressCtrl; 57 | for (auto pairIt = cmb->stateList.begin(); pairIt != cmb->stateList.end(); ++pairIt){ 58 | progStartState.push_back(std::make_pair(pairIt->first, 0.0)); 59 | progDeltaState.push_back(std::make_pair(pairIt->first, pairIt->second)); 60 | } 61 | } 62 | } 63 | 64 | Traversal::Traversal( 65 | const std::string &name, Progression* prog, size_t index, 66 | const ComboPairs &startPairs, const ComboPairs &endPairs, ComboSolve solveType): 67 | ShapeController(name, prog, index), exact(true){ 68 | 69 | std::unordered_map startSliders, endSliders; 70 | std::unordered_set allSliders; 71 | 72 | for (size_t i=0; isecond)); 92 | } 93 | else if (endIt == endSliders.end()){ 94 | // means slider exists in start, but not end 95 | progStartState.push_back(std::make_pair(sli, startIt->second)); 96 | progDeltaState.push_back(std::make_pair(sli, -startIt->second)); 97 | } 98 | else { 99 | if (startIt->second == endIt->second){ 100 | // if the values are the same, add it to the multiplier state 101 | multState.push_back(std::make_pair(sli, startIt->second)); 102 | } 103 | else { 104 | // if the values are different, add them to ther respective states 105 | progStartState.push_back(std::make_pair(sli, startIt->second)); 106 | progDeltaState.push_back(std::make_pair(sli, endIt->second - startIt->second)); 107 | } 108 | } 109 | } 110 | } 111 | 112 | void Traversal::storeValue( 113 | const std::vector &values, 114 | const std::vector &posValues, 115 | const std::vector &clamped, 116 | const std::vector &inverses) { 117 | 118 | if (!enabled) return; 119 | 120 | double mul = 0.0, val = 0.0; 121 | solveState(multState, solveType, exact, mul); 122 | 123 | std::vector vals, tars; 124 | 125 | for (size_t i = 0; i < progStartState.size(); ++i) { 126 | vals.push_back(progStartState[i].first->getValue() - progStartState[i].second); 127 | tars.push_back(progDeltaState[i].second); 128 | } 129 | solveState(vals, tars, solveType, exact, val); 130 | 131 | value = val; 132 | multiplier = mul; 133 | } 134 | 135 | bool Traversal::parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp){ 136 | return parseJSONv2(val, index, simp); 137 | } 138 | 139 | bool Traversal::parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp){ 140 | if (!val.IsObject()) return false; 141 | 142 | CHECK_JSON_STRING(nameIt, "name", val) 143 | CHECK_JSON_INT(progIt, "prog", val) 144 | CHECK_JSON_STRING(ptIt, "progressType", val) 145 | CHECK_JSON_INT(pcIt, "progressControl", val) 146 | CHECK_JSON_BOOL(pfIt, "progressFlip", val) 147 | CHECK_JSON_STRING(mtIt, "multiplierType", val) 148 | CHECK_JSON_INT(mcIt, "multiplierControl", val) 149 | CHECK_JSON_BOOL(mfIt, "multiplierFlip", val) 150 | 151 | std::string name(nameIt->value.GetString()); 152 | size_t pidx = (size_t)progIt->value.GetInt(); 153 | std::string pctype(ptIt->value.GetString()); 154 | std::string mctype(mtIt->value.GetString()); 155 | size_t pcidx = (size_t)pcIt->value.GetInt(); 156 | size_t mcidx = (size_t)mcIt->value.GetInt(); 157 | bool pcFlip = pfIt->value.GetBool(); 158 | bool mcFlip = mfIt->value.GetBool(); 159 | 160 | ShapeController *pcItem; 161 | if (!pctype.empty() && pctype[0] == 'S') { 162 | if (pcidx >= simp->sliders.size()) return false; 163 | pcItem = &simp->sliders[pcidx]; 164 | } 165 | else { 166 | if (pcidx >= simp->combos.size()) return false; 167 | pcItem = &simp->combos[pcidx]; 168 | } 169 | 170 | ShapeController *mcItem; 171 | if (!mctype.empty() && mctype[0] == 'S') { 172 | if (mcidx >= simp->sliders.size()) return false; 173 | mcItem = &simp->sliders[mcidx]; 174 | } 175 | else { 176 | if (mcidx >= simp->combos.size()) return false; 177 | mcItem = &simp->combos[mcidx]; 178 | } 179 | 180 | if (pidx >= simp->progs.size()) return false; 181 | 182 | bool enabled = getEnabled(val); 183 | 184 | simp->traversals.push_back(Traversal(name, &simp->progs[pidx], index, pcItem, mcItem, pcFlip, mcFlip)); 185 | simp->traversals.back().setEnabled(enabled); 186 | return true; 187 | } 188 | 189 | bool Traversal::parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp){ 190 | if (!val.IsObject()) return false; 191 | 192 | CHECK_JSON_STRING(nameIt, "name", val) 193 | CHECK_JSON_INT(progIt, "prog", val) 194 | CHECK_JSON_ARRAY(startIt, "start", val) 195 | CHECK_JSON_ARRAY(endIt, "end", val) 196 | 197 | ComboSolve solveType = getSolveType(val); 198 | 199 | bool isFloater = false; 200 | ComboPairs startPairs, endPairs; 201 | if (!getSolvePairs(startIt->value, simp, startPairs, isFloater)) return false; 202 | if (!getSolvePairs(endIt->value, simp, endPairs, isFloater)) return false; 203 | 204 | std::string name(nameIt->value.GetString()); 205 | size_t pidx = (size_t)progIt->value.GetInt(); 206 | if (pidx >= simp->progs.size()) return false; 207 | 208 | bool enabled = getEnabled(val); 209 | simp->traversals.push_back(Traversal(name, &simp->progs[pidx], index, startPairs, endPairs, solveType)); 210 | simp->traversals.back().setEnabled(enabled); 211 | return true; 212 | } 213 | -------------------------------------------------------------------------------- /src/lib/traversal.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "combo.h" 23 | #include "shapeController.h" 24 | #include "rapidjson/document.h" 25 | 26 | #include 27 | #include 28 | 29 | namespace simplex { 30 | 31 | class Progression; 32 | class Simplex; 33 | class Slider; 34 | 35 | 36 | class Traversal : public ShapeController { 37 | private: 38 | ComboPairs progStartState; 39 | ComboPairs progDeltaState; 40 | ComboPairs multState; 41 | ComboSolve solveType; 42 | bool exact; 43 | public: 44 | /* 45 | Traversal(const std::string &name, Progression* prog, size_t index, 46 | ShapeController* progressCtrl, ShapeController* multiplierCtrl, bool valueFlip, bool multiplierFlip): 47 | ShapeController(name, prog, index), progressCtrl(progressCtrl), multiplierCtrl(multiplierCtrl), 48 | valueFlip(valueFlip), multiplierFlip(multiplierFlip) {} 49 | */ 50 | 51 | Traversal(const std::string &name, Progression* prog, size_t index, ShapeController* progressCtrl, ShapeController* multiplierCtrl, bool valueFlip, bool multiplierFlip); 52 | Traversal(const std::string &name, Progression* prog, size_t index, const ComboPairs &startState, const ComboPairs &endState, ComboSolve solveType); 53 | 54 | void storeValue( 55 | const std::vector &values, 56 | const std::vector &posValues, 57 | const std::vector &clamped, 58 | const std::vector &inverses); 59 | static bool parseJSONv1(const rapidjson::Value &val, size_t index, Simplex *simp); 60 | static bool parseJSONv2(const rapidjson::Value &val, size_t index, Simplex *simp); 61 | static bool parseJSONv3(const rapidjson::Value &val, size_t index, Simplex *simp); 62 | }; 63 | 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/lib/trispace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | #include "trispace.h" 20 | #include "floater.h" 21 | #include "simplex.h" 22 | #include "slider.h" 23 | #include "utils.h" 24 | 25 | #include "math.h" 26 | #include "Eigen/Dense" 27 | 28 | #include // for all_of, sort 29 | #include // for accumulate 30 | #include 31 | #include 32 | #include 33 | 34 | using namespace simplex; 35 | 36 | // Check if the stateList of one floater is equal to another 37 | bool stateEq( 38 | std::vector> lhs, 39 | std::vector> rhs 40 | ){ 41 | for (size_t i=0; i TriSpace::buildSpaces(std::vector &floaters){ 49 | // group floaters by subspace dimension span 50 | std::vector> dimmed; 51 | for (auto fit = floaters.begin(); fit!=floaters.end(); ++fit){ 52 | //for (auto &floater : floaters){ 53 | auto &floater = *fit; 54 | size_t sls = floater.stateList.size(); 55 | if (sls >= dimmed.size()) dimmed.resize(sls+1); 56 | dimmed[sls].push_back(&floater); 57 | } 58 | 59 | // Go through each dimension group and separate them by shared 60 | // sliders and directions 61 | std::vector spaces; 62 | for ( auto dit = dimmed.begin(); dit != dimmed.end(); ++dit){ 63 | //for (auto &dim : dimmed){ 64 | auto &dim = *dit; 65 | std::vector bucket; 66 | std::vector used(dim.size()); 67 | for (size_t i=0; istateList, dim[j]->stateList)){ 76 | used[j] = true; 77 | bucket.push_back(dim[j]); 78 | } 79 | } 80 | spaces.push_back(TriSpace(bucket)); 81 | } 82 | } 83 | return spaces; 84 | } 85 | 86 | TriSpace::TriSpace(std::vector floaters):floaters(floaters){ 87 | triangulate(); 88 | } 89 | 90 | void TriSpace::triangulate(){ 91 | std::unordered_map< 92 | std::vector, 93 | std::vector>, 94 | vectorHash 95 | > d; 96 | 97 | for ( auto fit = floaters.begin(); fit != floaters.end(); ++fit){ 98 | //for (auto f : floaters){ 99 | auto &f = *fit; 100 | std::vector userPoint; 101 | for (auto sit = f->stateList.begin(); sit != f->stateList.end(); ++sit){ 102 | //for (auto sp : stateList){ 103 | auto &sp = *sit; 104 | userPoint.push_back(sp.second); 105 | } 106 | userPoints.push_back(userPoint); 107 | std::vector> rawSimps = pointToAdjSimp(userPoint); 108 | for ( auto rit = rawSimps.begin(); rit != rawSimps.end(); ++rit){ 109 | //for (auto &rawSimp : rawSimps){ 110 | auto &rawSimp = *rit; 111 | d[rawSimp].push_back(userPoint); 112 | } 113 | } 114 | 115 | for (auto pit = d.begin(); pit != d.end(); ++pit){ 116 | //for (auto p : d){ 117 | auto p = *pit; 118 | overrideSimplices.push_back(p.first); 119 | std::vector> singleSimp; 120 | singleSimp.push_back(p.first); 121 | auto ext = splitSimps(p.second, singleSimp); 122 | for (auto uit = ext.begin(); uit != ext.end(); ++uit){ 123 | //for (auto &userSimplex : ext){ 124 | auto &userSimplex = *uit; 125 | std::vector newSimp; 126 | for (size_t cIdx=0; cIdx &values, 143 | const std::vector &posValues, 144 | const std::vector &clamped, 145 | const std::vector &inverses 146 | ){ 147 | std::vector subInverse; 148 | std::vector vec; 149 | // All floats in a trispace share the same span 150 | // so I only need to check one of them 151 | for (auto pit = floaters[0]->stateList.begin(); pit != floaters[0]->stateList.end(); ++pit){ 152 | //for (auto &p : floaters[0]->stateList) { 153 | auto &p = *pit; 154 | size_t idx = p.first->getIndex(); 155 | subInverse.push_back(inverses[idx]); 156 | double cval = clamped[idx]; 157 | if (isZero(cval)) return; 158 | vec.push_back(cval); 159 | } 160 | if (floaters[0]->inverted != subInverse) return; 161 | 162 | std::vector majorSimp = pointToSimp(vec); 163 | size_t c = simplexMap.count(majorSimp); 164 | if (c == 0) return; 165 | 166 | std::vector> &simps = simplexMap[majorSimp]; 167 | 168 | 169 | for (auto sit = simps.begin(); sit != simps.end(); ++sit){ 170 | //for (auto &simp : simps){ 171 | auto &simp = *sit; 172 | std::vector> expanded; 173 | std::vector floaterCorners; 174 | // TODO: Didn't fill "expanded" properly 175 | userSimplexToCorners(simp, majorSimp, expanded, floaterCorners); 176 | 177 | std::vector b = barycentric(expanded, vec); 178 | if (std::all_of(b.begin(), b.end(), isPositive)){ 179 | for (size_t i = 0; i < b.size(); ++i) { 180 | int fcIdx = floaterCorners[i]; 181 | if (fcIdx != -1) { 182 | floaters[fcIdx]->value = b[i]; 183 | } 184 | } 185 | break; 186 | } 187 | } 188 | } 189 | 190 | std::vector> TriSpace::pointToAdjSimp( 191 | const std::vector &pt, 192 | double eps 193 | ) { 194 | //Search for simplices that are near the point 195 | //This allows for splitting the simplex, or snapping a 196 | //point to a nearby progression 197 | 198 | // Point, OrderedValues, CurrentSimplex, Output 199 | 200 | std::vector > out; 201 | std::vector rn, simp; 202 | rn.resize(pt.size()); 203 | for (int i=0; i &point, 213 | const std::vector &oVals, 214 | const std::vector &simp, 215 | std::vector > &out, 216 | double eps 217 | ) const { 218 | if (point.empty()){ 219 | out.push_back(simp); 220 | return; 221 | } 222 | 223 | double maxabs = fabs(point[0]); 224 | for (size_t i=0; i maxabs){ 227 | maxabs = aa; 228 | } 229 | } 230 | 231 | std::vector mxs; 232 | for (size_t i=0; i subpoint; 239 | std::vector subvals, nSimp; 240 | bool mvZero = isZero(maxabs); 241 | 242 | for (size_t i=0; i searchDirection; 244 | // zero is both positive and negative 245 | // so I need to do both directions 246 | size_t mx = mxs[i]; 247 | if (mvZero){ 248 | searchDirection.push_back(-1); 249 | searchDirection.push_back(1); 250 | } 251 | else { 252 | int p = (isPositive(point[mx])) ? 1 : -1; 253 | searchDirection.push_back(p); 254 | } 255 | 256 | //for (int direction : searchDirection){ 257 | for (auto dit = searchDirection.begin(); dit != searchDirection.end(); ++dit) { 258 | int direction = *dit; 259 | int newval = (oVals[mx] + 1) * direction; 260 | 261 | // Copy 262 | nSimp = simp; 263 | subpoint = point; 264 | subvals = oVals; 265 | 266 | nSimp.insert(nSimp.end(), newval); 267 | subpoint.erase(subpoint.begin()+mx); 268 | subvals.erase(subvals.begin()+mx); 269 | TriSpace::rec(subpoint, subvals, nSimp, out, eps); 270 | } 271 | } 272 | } 273 | 274 | std::vector > TriSpace::simplexToCorners( 275 | const std::vector &simplex 276 | ) const { 277 | std::vector currVec(simplex.size() - 1, 0.0); 278 | std::vector > out; 279 | for (size_t i = 0; i 0) ? s : -s; 286 | double val = (s > 0) ? 1.0 : -1.0; 287 | 288 | if (idx >= simplex.size()) { 289 | idx = idx - int(simplex.size()); 290 | out.push_back(this->userPoints[idx]); 291 | } 292 | else { 293 | currVec[idx - 1] = val; 294 | out.push_back(currVec); 295 | } 296 | } 297 | return out; 298 | } 299 | 300 | std::vector > > TriSpace::splitSimps( 301 | const std::vector > &pts, 302 | const std::vector > &simps 303 | ) const { 304 | std::vector > > out, tmpList; 305 | for (size_t i = 0; i &p = pts[i]; 311 | tmpList.clear(); 312 | for (size_t j = 0; j bary = barycentric(out[j], p); 314 | if (std::all_of(bary.begin(), bary.end(), isPositive)) { 315 | for (size_t k = 0; k> ns = out[j]; 319 | ns[k] = p; 320 | tmpList.push_back(std::move(ns)); 321 | } 322 | } 323 | } 324 | else { 325 | tmpList.push_back(out[j]); 326 | } 327 | } 328 | out = tmpList; 329 | } 330 | return out; 331 | } 332 | 333 | std::vector TriSpace::barycentric( 334 | const std::vector> &simplex, 335 | const std::vector &p 336 | ) const { 337 | 338 | std::vector last = simplex.back(); 339 | 340 | // lastVec = (p - last) 341 | Eigen::VectorXd lastVec(p.size()); 342 | for (size_t i=0; i out(&outArray[0],&outArray[p.size()]); 359 | double sum = accumulate(out.begin(), out.end(), 0.0); 360 | out.push_back(1.0 - sum); // 1-sum = missing value 361 | return out; 362 | } 363 | 364 | std::vector TriSpace::pointToSimp(const std::vector &pt) { 365 | /* 366 | Each simplex can be represented as a permutation of [(+-)(i+1) for i in range(len(dim))] 367 | So I will encode these values by the pos/neg direction along a dimension number. 368 | We always start at 0, so that makes [0,-2,4,1,-3] a valid encoding 369 | 370 | The resultant simplex is called a "Schlafli Orthoscheme" 371 | */ 372 | std::vector > abspt; 373 | double v; 374 | int idx, i, n; 375 | for (i=0; i &a, const std::pair &b) { 383 | return a.second < b.second; 384 | } 385 | ); 386 | 387 | std::vector out; 388 | out.push_back(0); 389 | for (i=int(abspt.size()); i>0; --i){ 390 | out.push_back(abspt[i-1].first); 391 | } 392 | return out; 393 | } 394 | 395 | void TriSpace::userSimplexToCorners( 396 | const std::vector &simplex, 397 | const std::vector &original, 398 | std::vector> &out, 399 | std::vector &floaterCorners // TODO 400 | ) const{ 401 | 402 | std::vector currVec (simplex.size()-1, 0.0); 403 | for (size_t i=0; i 0)? s : -s; 413 | 414 | // get the original idx 415 | int oidx = (os > 0)? os : -os; 416 | double val = (os > 0)? 1.0 : -1.0; 417 | 418 | if (oidx != 0){ 419 | // keep track of where we *would* be normally 420 | // unless we're replacing the first item 421 | currVec[oidx-1] = val; 422 | } 423 | 424 | // if the user idx is too high 425 | if (idx >= simplex.size()){ 426 | // grab a user point 427 | idx = idx - int(simplex.size()); 428 | out.push_back(this->userPoints[idx]); 429 | floaterCorners.push_back(idx); 430 | } 431 | else { 432 | // get the currVec 433 | out.push_back(currVec); 434 | floaterCorners.push_back(-1); 435 | } 436 | } 437 | } 438 | 439 | -------------------------------------------------------------------------------- /src/lib/trispace.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "enums.h" 23 | #include "utils.h" 24 | #include 25 | #include 26 | 27 | namespace simplex { 28 | 29 | class Floater; 30 | 31 | class TriSpace { 32 | private: 33 | // Correlates the auto-generated simplex with the user-created simplices 34 | // resulting from the splitting procedure 35 | std::unordered_map, std::vector>, vectorHash> simplexMap; 36 | std::vector> userPoints; 37 | std::vector> overrideSimplices; 38 | 39 | std::vector floaters; 40 | std::vector barycentric(const std::vector> &simplex, const std::vector &p) const; 41 | //static std::vector> simplexToCorners(const std::vector &simplex); 42 | std::vector pointToSimp(const std::vector &pt); 43 | std::vector> pointToAdjSimp(const std::vector &pt, double eps=0.01); 44 | void triangulate(); // convenience function for separating the data access from the actual math 45 | // Code to split a list of simplices by a list of points, only used in triangulate() 46 | std::vector>> splitSimps(const std::vector> &pts, const std::vector> &simps) const; 47 | std::vector > simplexToCorners(const std::vector &simplex) const; 48 | void rec(const std::vector &point, const std::vector &oVals, const std::vector &simp, std::vector > &out, double eps) const; 49 | 50 | // break down the given simplex encoding to a list of corner points for the barycentric solver and 51 | // a correlation of the point index to the floater index (or size_t_MAX if invalid) 52 | void userSimplexToCorners( 53 | const std::vector &simplex, 54 | const std::vector &original, 55 | std::vector> &out, 56 | std::vector &floaterCorners 57 | ) const; 58 | 59 | public: 60 | // Take the non-related floaters and group them by shared span and orthant 61 | static std::vector buildSpaces(std::vector &floaters); 62 | TriSpace(std::vector floaters); 63 | void storeValue( 64 | const std::vector &values, 65 | const std::vector &posValues, 66 | const std::vector &clamped, 67 | const std::vector &inverses); 68 | }; 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/lib/utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | #include "utils.h" 22 | #include "math.h" 23 | #include 24 | #include 25 | #include 26 | 27 | namespace simplex{ 28 | 29 | void rectify( 30 | const std::vector &rawVec, 31 | std::vector &values, 32 | std::vector &clamped, 33 | std::vector &inverses 34 | ){ 35 | // Rectifying just makes everything positive, keeps track of the inversion, and applies clamping 36 | values.resize(rawVec.size()); 37 | clamped.resize(rawVec.size()); 38 | inverses.resize(rawVec.size()); 39 | for (size_t i=0; i MAXVAL) ? MAXVAL : v; 47 | } 48 | } 49 | 50 | double doSoftMin(double X, double Y) { 51 | if (isZero(X) || isZero(Y)) return 0.0; 52 | if (X < Y) std::swap(X, Y); 53 | 54 | double n = 4.0; 55 | double h = 0.025; 56 | double p = 2.0; 57 | double q = 1.0 / p; 58 | 59 | double d = 2.0 * (pow(1.0 + h, q) - pow(h, q)); 60 | double s = pow(h, q); 61 | double z = pow(pow(X, p) + h, q) + pow(pow(Y, p) + h, q) - pow(pow(X - Y, p) + h, q); 62 | return (z - s) / d; 63 | } 64 | } // namespace simplex 65 | -------------------------------------------------------------------------------- /src/lib/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include // for hash 24 | #include "rapidjson/document.h" 25 | #include "math.h" 26 | 27 | #define CHECK_JSON_STRING(jsIt, jsName, jsVal) \ 28 | auto (jsIt) = (jsVal).FindMember(jsName); \ 29 | if ((jsIt) == (jsVal).MemberEnd()) return false; \ 30 | if (!(jsIt)->value.IsString()) return false; 31 | 32 | #define CHECK_JSON_BOOL(jsIt, jsName, jsVal) \ 33 | auto (jsIt) = (jsVal).FindMember(jsName); \ 34 | if ((jsIt) == (jsVal).MemberEnd()) return false; \ 35 | if (!(jsIt)->value.IsBool()) return false; 36 | 37 | #define CHECK_JSON_INT(jsIt, jsName, jsVal) \ 38 | auto (jsIt) = (jsVal).FindMember(jsName); \ 39 | if ((jsIt) == (jsVal).MemberEnd()) return false; \ 40 | if (!(jsIt)->value.IsInt()) return false; 41 | 42 | #define CHECK_JSON_ARRAY(jsIt, jsName, jsVal) \ 43 | auto (jsIt) = (jsVal).FindMember(jsName); \ 44 | if ((jsIt) == (jsVal).MemberEnd()) return false; \ 45 | if (!(jsIt)->value.IsArray()) return false; 46 | 47 | 48 | namespace simplex { 49 | const double EPS = 1e-6; 50 | const int ULPS = 4; 51 | const double MAXVAL = 1.0; // max clamping value 52 | 53 | inline bool floatEQ(const double A, const double B, const double eps) { 54 | // from https://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format 55 | // Check if the numbers are really close -- needed 56 | // when comparing numbers near zero. 57 | double absDiff = fabs(A - B); 58 | if (absDiff <= eps) 59 | return true; 60 | return false; 61 | } 62 | 63 | inline bool isZero(const double a) { return floatEQ(a, 0.0, EPS); } 64 | inline bool isPositive(const double a) { return a > -EPS; } 65 | inline bool isNegative(const double a) { return a < EPS; } 66 | 67 | void rectify( 68 | const std::vector &rawVec, 69 | std::vector &values, 70 | std::vector &clamped, 71 | std::vector &inverses 72 | ); 73 | 74 | double doSoftMin(double X, double Y); 75 | 76 | template 77 | struct vectorHash { 78 | size_t operator()(const std::vector & val) const { 79 | // this is the python tuple hashing algorithm 80 | size_t value = 0x345678; 81 | size_t vSize = val.size(); 82 | std::hash iHash; 83 | for (auto i = val.begin(); i != val.end(); ++i) { 84 | value = (1000003 * value) ^ iHash(*i); 85 | value = value ^ vSize; 86 | } 87 | return value; 88 | } 89 | }; 90 | 91 | } // namespace simplex 92 | -------------------------------------------------------------------------------- /src/maya/pluginMain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #include "simplex_mayaNode.h" 21 | #include 22 | #include 23 | #include 24 | 25 | MStatus initializePlugin( MObject obj ) 26 | { 27 | MStatus status; 28 | MFnPlugin plugin( obj, "", "2016", "Any"); 29 | 30 | status = plugin.registerNode( "simplex_maya", simplex_maya::id, simplex_maya::creator, 31 | simplex_maya::initialize ); 32 | if (!status) { 33 | status.perror("registerNode"); 34 | return status; 35 | } 36 | 37 | return status; 38 | } 39 | 40 | MStatus uninitializePlugin( MObject obj) 41 | { 42 | MStatus status; 43 | MFnPlugin plugin( obj ); 44 | 45 | status = plugin.deregisterNode( simplex_maya::id ); 46 | if (!status) { 47 | status.perror("deregisterNode"); 48 | return status; 49 | } 50 | 51 | return status; 52 | } 53 | -------------------------------------------------------------------------------- /src/maya/simplex_mayaNode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #include "simplex_mayaNode.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define CHECKSTAT(s) if (!(s)) { (s).perror("attributeAffects"); return (s);} 29 | 30 | #ifdef __linux__ 31 | typedef unsigned int UINT; 32 | #endif 33 | 34 | MTypeId simplex_maya::id(0x001226C8); 35 | 36 | // Attribute list 37 | MObject simplex_maya::aSliders; 38 | MObject simplex_maya::aWeights; 39 | MObject simplex_maya::aDefinition; 40 | MObject simplex_maya::aMinorUpdate; 41 | MObject simplex_maya::aExactSolve; 42 | 43 | 44 | simplex_maya::simplex_maya() { 45 | this->sPointer = new simplex::Simplex(); 46 | } 47 | simplex_maya::~simplex_maya() { 48 | delete this->sPointer; 49 | } 50 | 51 | MStatus simplex_maya::compute(const MPlug& plug, MDataBlock& data) { 52 | MStatus status; 53 | if( plug == aWeights ) { 54 | MArrayDataHandle inputData = data.inputArrayValue(aSliders, &status); 55 | CHECKSTAT(status); 56 | 57 | std::vector inVec; 58 | inVec.resize(inputData.elementCount()); 59 | 60 | // Read the input value from the handle. 61 | for (UINT physIdx = 0; physIdx < inputData.elementCount(); ++physIdx){ 62 | inputData.jumpToArrayElement(physIdx); 63 | auto valueHandle = inputData.inputValue(&status); 64 | CHECKSTAT(status); 65 | UINT trueIdx = inputData.elementIndex(); 66 | if (trueIdx >= inVec.size()){ 67 | inVec.resize(trueIdx+1); 68 | } 69 | inVec[trueIdx] = valueHandle.asDouble(); 70 | } 71 | 72 | if (!simplexIsValid || !this->sPointer->loaded){ 73 | MDataHandle jsonData = data.inputValue(aDefinition, &status); 74 | CHECKSTAT(status); 75 | MString ss = jsonData.asString(); 76 | std::string sss(ss.asChar(), ss.length()); 77 | this->sPointer->clear(); 78 | this->sPointer->parseJSON(sss); 79 | this->sPointer->build(); 80 | 81 | simplexIsValid = true; 82 | if (this->sPointer->hasParseError){ 83 | cerr << "JSON PARSE ERROR: " << this->sPointer->parseError << 84 | " \n At offset: " << std::to_string(this->sPointer->parseErrorOffset) << "\n"; 85 | return MS::kFailure; 86 | } 87 | } 88 | 89 | if (this->sPointer->loaded){ 90 | MDataHandle exactSolve = data.inputValue(aExactSolve, &status); 91 | CHECKSTAT(status); 92 | this->sPointer->setExactSolve(exactSolve.asBool()); 93 | } 94 | 95 | inVec.resize(this->sPointer->sliderLen()); 96 | 97 | if (!cacheIsValid){ 98 | cacheIsValid = true; 99 | this->sPointer->clearValues(); 100 | cache = this->sPointer->solve(inVec); 101 | } 102 | 103 | // Set the output weights 104 | MArrayDataHandle outputArrayHandle = data.outputArrayValue(simplex_maya::aWeights, &status); 105 | CHECKSTAT(status); 106 | for (UINT physIdx = 0; physIdx < outputArrayHandle.elementCount(); ++physIdx){ 107 | outputArrayHandle.jumpToArrayElement(physIdx); 108 | UINT trueIdx = outputArrayHandle.elementIndex(); 109 | auto outHandle = outputArrayHandle.outputValue(&status); 110 | CHECKSTAT(status); 111 | if (trueIdx < cache.size()) { 112 | // because the cache size can change 113 | outHandle.setDouble(cache[trueIdx]); 114 | } 115 | } 116 | 117 | outputArrayHandle.setAllClean(); 118 | data.setClean(plug); 119 | } 120 | else { 121 | return MS::kUnknownParameter; 122 | } 123 | 124 | return MS::kSuccess; 125 | } 126 | 127 | MStatus simplex_maya::preEvaluation(const MDGContext& context, const MEvaluationNode& evaluationNode){ 128 | MStatus status; 129 | if (context.isNormal()){ 130 | if (evaluationNode.dirtyPlugExists(aDefinition, &status) && status){ 131 | this->simplexIsValid = false; 132 | this->cacheIsValid = false; 133 | } 134 | if (evaluationNode.dirtyPlugExists(aSliders, &status) && status){ 135 | this->cacheIsValid = false; 136 | } 137 | if (evaluationNode.dirtyPlugExists(aExactSolve, &status) && status){ 138 | this->cacheIsValid = false; 139 | } 140 | } 141 | else { 142 | return MS::kFailure; 143 | } 144 | return MS::kSuccess; 145 | } 146 | 147 | MStatus simplex_maya::setDependentsDirty(const MPlug& plug, MPlugArray& plugArray){ 148 | if (plug == aDefinition){ 149 | this->simplexIsValid = false; 150 | this->cacheIsValid = false; 151 | } 152 | if (plug == aSliders){ 153 | this->cacheIsValid = false; 154 | } 155 | if (plug == aExactSolve){ 156 | this->cacheIsValid = false; 157 | } 158 | return MPxNode::setDependentsDirty(plug, plugArray); 159 | } 160 | 161 | void* simplex_maya::creator(){ 162 | return new simplex_maya(); 163 | } 164 | 165 | MStatus simplex_maya::initialize(){ 166 | MFnNumericAttribute nAttr; 167 | MFnTypedAttribute tAttr; 168 | MFnStringData sData; 169 | MStatus status, status2; 170 | 171 | // Input sliders 172 | simplex_maya::aMinorUpdate = nAttr.create("minorUpdate", "mu", MFnNumericData::kBoolean, false, &status); 173 | CHECKSTAT(status); 174 | nAttr.setKeyable(false); 175 | nAttr.setReadable(true); 176 | nAttr.setWritable(true); 177 | status = simplex_maya::addAttribute(simplex_maya::aMinorUpdate); 178 | CHECKSTAT(status); 179 | 180 | simplex_maya::aExactSolve = nAttr.create("exactSolve", "es", MFnNumericData::kBoolean, true, &status); 181 | CHECKSTAT(status); 182 | nAttr.setKeyable(false); 183 | nAttr.setReadable(true); 184 | nAttr.setWritable(true); 185 | status = simplex_maya::addAttribute(simplex_maya::aExactSolve); 186 | CHECKSTAT(status); 187 | 188 | simplex_maya::aDefinition = tAttr.create("definition", "d", MFnData::kString, sData.create(&status2), &status); 189 | CHECKSTAT(status); 190 | CHECKSTAT(status2); 191 | tAttr.setStorable(true); 192 | tAttr.setKeyable(true); 193 | status = simplex_maya::addAttribute(simplex_maya::aDefinition); 194 | CHECKSTAT(status); 195 | 196 | // Input sliders 197 | simplex_maya::aSliders = nAttr.create("sliders", "s", MFnNumericData::kDouble, 0.0, &status); 198 | CHECKSTAT(status); 199 | nAttr.setKeyable(true); 200 | nAttr.setReadable(false); 201 | nAttr.setWritable(true); 202 | nAttr.setArray(true); 203 | nAttr.setUsesArrayDataBuilder(true); 204 | status = simplex_maya::addAttribute(simplex_maya::aSliders); 205 | CHECKSTAT(status); 206 | 207 | // Output weights 208 | simplex_maya::aWeights = nAttr.create("weights", "w", MFnNumericData::kDouble, 0.0, &status); 209 | CHECKSTAT(status); 210 | nAttr.setStorable(false); 211 | nAttr.setReadable(true); 212 | nAttr.setWritable(false); 213 | nAttr.setArray(true); 214 | nAttr.setUsesArrayDataBuilder(true); 215 | status = simplex_maya::addAttribute(simplex_maya::aWeights); 216 | CHECKSTAT(status); 217 | 218 | // Set data dependencies 219 | status = attributeAffects(aSliders, aWeights); 220 | CHECKSTAT(status); 221 | status = attributeAffects(aDefinition, aWeights); 222 | CHECKSTAT(status); 223 | 224 | return MS::kSuccess; 225 | } 226 | 227 | -------------------------------------------------------------------------------- /src/maya/simplex_mayaNode.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "simplex.h" 33 | 34 | class simplex_maya : public MPxNode 35 | { 36 | public: 37 | simplex_maya(); 38 | virtual ~simplex_maya(); 39 | 40 | virtual MStatus compute( const MPlug& plug, MDataBlock& data ); 41 | virtual MStatus preEvaluation(const MDGContext& context, const MEvaluationNode& evaluationNode); 42 | virtual MStatus setDependentsDirty(const MPlug& plug, MPlugArray& plugArray); 43 | static void* creator(); 44 | static MStatus initialize(); 45 | 46 | public: 47 | static MObject aSliders; 48 | static MObject aWeights; 49 | static MObject aDefinition; 50 | static MObject aMinorUpdate; 51 | static MObject aExactSolve; 52 | 53 | static MTypeId id; 54 | 55 | 56 | private: 57 | simplex::Simplex * sPointer; 58 | std::vector cache; 59 | bool simplexIsValid = false; 60 | bool cacheIsValid = false; 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /src/python/simplex_python.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "simplex.h" 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct { 10 | PyObject_HEAD // No Semicolon for this Macro; 11 | PyObject *definition; 12 | simplex::Simplex *sPointer; 13 | } PySimplex; 14 | 15 | static void 16 | PySimplex_dealloc(PySimplex* self) { 17 | Py_XDECREF(self->definition); 18 | if (self->sPointer != NULL) 19 | delete self->sPointer; 20 | Py_TYPE(self)->tp_free((PyObject*)self); 21 | } 22 | 23 | static PyObject * 24 | PySimplex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { 25 | PySimplex *self; 26 | self = (PySimplex *)type->tp_alloc(type, 0); 27 | if (self != NULL) { 28 | self->definition = PyUnicode_FromString(""); 29 | if (self->definition == NULL) { 30 | Py_DECREF(self); 31 | return NULL; 32 | } 33 | self->sPointer = new simplex::Simplex(); 34 | } 35 | 36 | return (PyObject *)self; 37 | } 38 | 39 | static PyObject * 40 | PySimplex_getdefinition(PySimplex* self, void* closure){ 41 | Py_INCREF(self->definition); 42 | return self->definition; 43 | } 44 | 45 | static int 46 | PySimplex_setdefinition(PySimplex* self, PyObject* jsValue, void* closure){ 47 | if (jsValue == NULL || jsValue == Py_None){ 48 | jsValue = PyUnicode_FromString(""); 49 | } 50 | 51 | if (! PyUnicode_Check(jsValue)) { 52 | PyErr_SetString(PyExc_TypeError, "The simplex definition must be a string"); 53 | return -1; 54 | } 55 | 56 | PyObject *tmp = self->definition; 57 | Py_INCREF(jsValue); 58 | self->definition = jsValue; 59 | Py_DECREF(tmp); 60 | 61 | #if PY_MAJOR_VERSION >= 3 62 | // Get the unicode as a wstring, and a wstring to string converter 63 | std::wstring simDefw = std::wstring(PyUnicode_AsWideCharString(self->definition, NULL)); 64 | std::wstring_convert> myconv; 65 | std::string simDef = myconv.to_bytes(simDefw); 66 | #else 67 | std::string simDef = std::string(PyString_AsString(self->definition); 68 | #endif 69 | // set the definition in the solver 70 | self->sPointer->clear(); 71 | self->sPointer->parseJSON(simDef); 72 | self->sPointer->build(); 73 | 74 | return 0; 75 | } 76 | 77 | static PyObject * 78 | PySimplex_getexactsolve(PySimplex* self, void* closure){ 79 | if (self->sPointer->getExactSolve()){ 80 | Py_RETURN_TRUE; 81 | } 82 | Py_RETURN_FALSE; 83 | } 84 | 85 | static int 86 | PySimplex_setexactsolve(PySimplex* self, PyObject* exact, void* closure){ 87 | int truthy = PyObject_IsTrue(exact); 88 | if (truthy == -1){ 89 | PyErr_SetString(PyExc_TypeError, "The value passed cannot be cast to boolean"); 90 | return -1; 91 | } 92 | 93 | self->sPointer->setExactSolve((truthy == 1)); 94 | return 0; 95 | } 96 | 97 | static int 98 | PySimplex_init(PySimplex *self, PyObject *args, PyObject *kwds) { 99 | PyObject *jsValue=NULL, *tmp=NULL; 100 | static char *kwlist[] = {"jsValue", NULL}; 101 | 102 | if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &jsValue)) 103 | return -1; 104 | 105 | return PySimplex_setdefinition(self, jsValue, NULL); 106 | } 107 | 108 | static PyObject * 109 | PySimplex_solve(PySimplex* self, PyObject* vec){ 110 | if (! PySequence_Check(vec)){ 111 | PyErr_SetString(PyExc_TypeError, "Input must be a list or tuple"); 112 | return NULL; 113 | } 114 | 115 | PyObject *item; 116 | std::vector stdVec, outVec; 117 | for (Py_ssize_t i=0; isPointer->clearValues(); 128 | outVec = self->sPointer->solve(stdVec); 129 | 130 | PyObject *out = PyList_New(outVec.size()); 131 | for (size_t i=0; i stdVec, outVec; 183 | stdVec.resize((size_t)inView.shape[0]); 184 | Py_ssize_t inSize = inView.itemsize; 185 | 186 | char *iptr = (char *)inView.buf; 187 | for (Py_ssize_t i = 0; isPointer->clearValues(); 198 | outVec = self->sPointer->solve(stdVec); 199 | 200 | if (outView.shape[0] < outVec.size()){ 201 | PyErr_SetString(PyExc_ValueError, "Output must have enough space allocated"); 202 | PyBuffer_Release(&inView); 203 | PyBuffer_Release(&outView); 204 | return NULL; 205 | } 206 | 207 | Py_ssize_t outSize = outView.itemsize; 208 | if (outSize == sizeof(double)){ 209 | memcpy(outView.buf, outVec.data(), outVec.size() * sizeof(double)); 210 | } 211 | else { 212 | std::vector outFloatVec; 213 | outFloatVec.resize(outVec.size()); 214 | std::copy(outVec.begin(), outVec.end(), outFloatVec.begin()); 215 | memcpy(outView.buf, outVec.data(), outFloatVec.size()*sizeof(float)); 216 | } 217 | 218 | PyBuffer_Release(&inView); 219 | PyBuffer_Release(&outView); 220 | Py_RETURN_NONE; 221 | } 222 | 223 | 224 | 225 | static PyGetSetDef PySimplex_getseters[] = { 226 | {"definition", 227 | (getter)PySimplex_getdefinition, (setter)PySimplex_setdefinition, 228 | "Simplex structure definition string", 229 | NULL}, 230 | 231 | {"exactSolve", 232 | (getter)PySimplex_getexactsolve, (setter)PySimplex_setexactsolve, 233 | "Run the solve with the exact min() solver", 234 | NULL}, 235 | {NULL} /* Sentinel */ 236 | }; 237 | 238 | static PyMethodDef PySimplex_methods[] = { 239 | {"solve", (PyCFunction)PySimplex_solve, METH_O, 240 | "Supply an input list to the solver, and recieve and output list" 241 | }, 242 | {"solveBuffer", (PyCFunction)PySimplex_solveBuffer, METH_VARARGS, 243 | "Supply an input list to the solver, and recieve and output buffer" 244 | }, 245 | {NULL} /* Sentinel */ 246 | }; 247 | 248 | static PyTypeObject PySimplexType = { 249 | PyVarObject_HEAD_INIT(NULL, 0) 250 | #if PY_MAJOR_VERSION >= 3 251 | "pysimplex3.PySimplex", /* tp_name */ 252 | #else 253 | "pysimplex.PySimplex", /* tp_name */ 254 | #endif 255 | sizeof(PySimplex), /* tp_basicsize */ 256 | 0, /* tp_itemsize */ 257 | (destructor)PySimplex_dealloc, /* tp_dealloc */ 258 | 0, /* tp_print */ 259 | 0, /* tp_getattr */ 260 | 0, /* tp_setattr */ 261 | 0, /* tp_compare */ 262 | 0, /* tp_repr */ 263 | 0, /* tp_as_number */ 264 | 0, /* tp_as_sequence */ 265 | 0, /* tp_as_mapping */ 266 | 0, /* tp_hash */ 267 | 0, /* tp_call */ 268 | 0, /* tp_str */ 269 | 0, /* tp_getattro */ 270 | 0, /* tp_setattro */ 271 | 0, /* tp_as_buffer */ 272 | Py_TPFLAGS_DEFAULT | 273 | Py_TPFLAGS_BASETYPE, /* tp_flags */ 274 | "PySimplex objects", /* tp_doc */ 275 | 0, /* tp_traverse */ 276 | 0, /* tp_clear */ 277 | 0, /* tp_richcompare */ 278 | 0, /* tp_weaklistoffset */ 279 | 0, /* tp_iter */ 280 | 0, /* tp_iternext */ 281 | PySimplex_methods, /* tp_methods */ 282 | 0, /* tp_members */ 283 | PySimplex_getseters, /* tp_getset */ 284 | 0, /* tp_base */ 285 | 0, /* tp_dict */ 286 | 0, /* tp_descr_get */ 287 | 0, /* tp_descr_set */ 288 | 0, /* tp_dictoffset */ 289 | (initproc)PySimplex_init, /* tp_init */ 290 | 0, /* tp_alloc */ 291 | PySimplex_new, /* tp_new */ 292 | }; 293 | 294 | static PyMethodDef module_methods[] = { 295 | {NULL} /* Sentinel */ 296 | }; 297 | 298 | 299 | 300 | static PyObject * localInit(void) 301 | { 302 | PyObject* m; 303 | 304 | if (PyType_Ready(&PySimplexType) < 0) 305 | return NULL; 306 | 307 | #if PY_MAJOR_VERSION >= 3 308 | static struct PyModuleDef moduledef = { 309 | PyModuleDef_HEAD_INIT, 310 | "pysimplex3", /* m_name */ 311 | "The Simplex blendshape solver in Python", /* m_doc */ 312 | -1, /* m_size */ 313 | module_methods, /* m_methods */ 314 | NULL, /* m_reload */ 315 | NULL, /* m_traverse */ 316 | NULL, /* m_clear */ 317 | NULL, /* m_free */ 318 | }; 319 | m = PyModule_Create(&moduledef); 320 | #else 321 | m = Py_InitModule3("pysimplex", module_methods, 322 | "The Simplex blendshape solver in Python"); 323 | #endif 324 | 325 | if (m == NULL) 326 | return NULL; 327 | 328 | Py_INCREF(&PySimplexType); 329 | PyModule_AddObject(m, "PySimplex", (PyObject *)&PySimplexType); 330 | return m; 331 | } 332 | 333 | #if PY_MAJOR_VERSION >= 3 334 | PyMODINIT_FUNC PyInit_pysimplex3(void) { 335 | return localInit(); 336 | } 337 | #else 338 | PyMODINIT_FUNC initpysimplex(void) { 339 | localInit(); 340 | } 341 | #endif 342 | -------------------------------------------------------------------------------- /src/xsi/simplex_ice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Blur Studio 3 | 4 | This file is part of Simplex. 5 | 6 | Simplex is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Simplex is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with Simplex. If not, see . 18 | */ 19 | 20 | #include "simplex_ice.h" 21 | 22 | using namespace XSI; 23 | using namespace simplex; 24 | 25 | 26 | 27 | 28 | // Defines port, group and map identifiers used for registering the ICENode 29 | enum IDs{ 30 | ID_IN_Revision = 0, 31 | ID_IN_Definition = 1, 32 | ID_IN_Sliders = 2, 33 | ID_G_100 = 100, 34 | ID_OUT_Weights = 200, 35 | ID_TYPE_CNS = 400, 36 | ID_STRUCT_CNS, 37 | ID_CTXT_CNS, 38 | ID_UNDEF = ULONG_MAX 39 | }; 40 | 41 | CStatus RegisterSimplexNode( PluginRegistrar& in_reg ); 42 | 43 | class Simplex_XSI { 44 | public: 45 | simplex::Simplex mysimplex; 46 | std::string storedDefinition; 47 | 48 | void updateDef(const std::string check){ 49 | // The *EXPECTED* result of this string comparison is equality 50 | // so adding extra tests to rule out equality early is a bad thing 51 | if (this->storedDefinition != check) { 52 | this->mysimplex.clear(); 53 | this->mysimplex.parseJSON(check); 54 | this->mysimplex.build(); 55 | } 56 | } 57 | 58 | const std::vector computeProgShapeValues(const std::vector &invec) { 59 | return this->mysimplex.solve(invec); 60 | } 61 | }; 62 | 63 | 64 | 65 | SICALLBACK XSILoadPlugin( PluginRegistrar& in_reg ){ 66 | in_reg.PutAuthor(L"tyler"); 67 | in_reg.PutName(L"SimplexNode Plugin"); 68 | in_reg.PutVersion(1,1); 69 | 70 | RegisterSimplexNode( in_reg ); 71 | 72 | //RegistrationInsertionPoint - do not remove this line 73 | 74 | return CStatus::OK; 75 | } 76 | 77 | SICALLBACK XSIUnloadPlugin( const PluginRegistrar& in_reg ){ 78 | CString strPluginName; 79 | strPluginName = in_reg.GetName(); 80 | Application().LogMessage(strPluginName + L" has been unloaded.",siVerboseMsg); 81 | return CStatus::OK; 82 | } 83 | 84 | CStatus RegisterSimplexNode( PluginRegistrar& in_reg ){ 85 | ICENodeDef nodeDef; 86 | nodeDef = Application().GetFactory().CreateICENodeDef(L"SimplexNode",L"SimplexNode"); 87 | 88 | CStatus st; 89 | st = nodeDef.PutColor(154,188,102); 90 | st.AssertSucceeded( ) ; 91 | 92 | st = nodeDef.PutThreadingModel(XSI::siICENodeSingleThreading); 93 | st.AssertSucceeded( ) ; 94 | 95 | // Add input ports and groups. 96 | st = nodeDef.AddPortGroup(ID_G_100); 97 | st.AssertSucceeded( ) ; 98 | 99 | // The revision number, for counting updates 100 | st = nodeDef.AddInputPort(ID_IN_Revision, 101 | ID_G_100, 102 | siICENodeDataLong, 103 | siICENodeStructureSingle, 104 | siICENodeContextSingleton, 105 | L"Revision", 106 | L"Revision", 107 | 0, 108 | CValue(), 109 | CValue(), 110 | ID_UNDEF, 111 | ID_UNDEF, 112 | ID_CTXT_CNS); 113 | st.AssertSucceeded(); 114 | 115 | // String definition 116 | st = nodeDef.AddInputPort(ID_IN_Definition, 117 | ID_G_100, 118 | siICENodeDataString, 119 | siICENodeStructureSingle, 120 | siICENodeContextSingleton, 121 | L"Definition", 122 | L"Definition", 123 | L"Default String", 124 | CValue(), 125 | CValue(), 126 | ID_UNDEF, 127 | ID_UNDEF, 128 | ID_CTXT_CNS); 129 | st.AssertSucceeded(); 130 | 131 | // input slider vector 132 | st = nodeDef.AddInputPort(ID_IN_Sliders, 133 | ID_G_100, 134 | siICENodeDataFloat, 135 | siICENodeStructureArray, 136 | siICENodeContextSingleton, 137 | L"Sliders", 138 | L"Sliders", 139 | 0, 140 | CValue(), 141 | CValue(), 142 | ID_UNDEF, 143 | ID_UNDEF, 144 | ID_CTXT_CNS); 145 | st.AssertSucceeded(); 146 | 147 | 148 | 149 | // Add output ports. 150 | st = nodeDef.AddOutputPort(ID_OUT_Weights, 151 | siICENodeDataFloat, 152 | siICENodeStructureArray, 153 | siICENodeContextSingleton, 154 | L"Weights", 155 | L"Weights", 156 | ID_UNDEF, 157 | ID_UNDEF, 158 | ID_CTXT_CNS); 159 | st.AssertSucceeded( ) ; 160 | 161 | PluginItem nodeItem = in_reg.RegisterICENode(nodeDef); 162 | nodeItem.PutCategories(L"Custom ICENode"); 163 | 164 | return CStatus::OK; 165 | } 166 | 167 | 168 | SICALLBACK SimplexNode_Evaluate( ICENodeContext& in_ctxt ){ 169 | // The current output port being evaluated... 170 | ULONG out_portID = in_ctxt.GetEvaluatedOutputPortID( ); 171 | 172 | switch( out_portID ){ 173 | case ID_OUT_Weights : 174 | { 175 | Simplex_XSI* simp = (Simplex_XSI*)(CValue::siPtrType)in_ctxt.GetUserData(); 176 | 177 | CDataArrayLong RevisionData(in_ctxt, ID_IN_Revision); 178 | 179 | // Note: Specific CIndexSet for Definition is required in single-threading mode 180 | CDataArrayString DefinitionData(in_ctxt, ID_IN_Definition); 181 | if (DefinitionData.GetCount() == 0) 182 | return CStatus::OK; 183 | //CIndexSet DefinitionIndexSet( in_ctxt, ID_IN_Definition ); 184 | std::string definition(DefinitionData[0].GetAsciiString()); 185 | simp->mysimplex.clear(); 186 | simp->updateDef(definition); 187 | bool exact = false; 188 | simp->mysimplex.setExactSolve(exact); 189 | 190 | // Note: Specific CIndexSet for Sliders is required in single-threading mode 191 | CDataArray2DFloat SlidersData(in_ctxt, ID_IN_Sliders); 192 | //CIndexSet SlidersIndexSet( in_ctxt, ID_IN_Sliders ); 193 | 194 | if (SlidersData.GetCount() == 0) 195 | return CStatus::OK; 196 | CDataArray2DFloat::Accessor SlidersSubArray = SlidersData[0]; 197 | ULONG ct = SlidersSubArray.GetCount(); 198 | 199 | if (ct == 0) 200 | return CStatus::OK; 201 | std::vector inVec(ct, 0.0f); 202 | for (ULONG i = 0; i < ct; i++){ 203 | inVec[i] = SlidersSubArray[i]; 204 | } 205 | 206 | inVec.resize(simp->mysimplex.sliderLen()); 207 | std::vector outVec; 208 | outVec = simp->computeProgShapeValues(inVec); 209 | 210 | // Get the output port array ... 211 | CDataArray2DFloat outData(in_ctxt); 212 | CDataArray2DFloat::Accessor outAcc = outData.Resize(0, outVec.size()); 213 | for (ULONG i = 0; i. 18 | */ 19 | 20 | #ifndef SIMPLEX_ICE_H 21 | #define SIMPLEX_ICE_H 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | #include "simplex.h" 53 | 54 | #endif /* SIMPLEX_ICE_H */ 55 | 56 | -------------------------------------------------------------------------------- /xsiConfigure.bat: -------------------------------------------------------------------------------- 1 | setlocal 2 | 3 | SET BUILD=xsibuild 4 | SET COMPILER=Visual Studio 10 2010 Win64 5 | 6 | SET PFX=%~dp0 7 | cd %PFX% 8 | rmdir %BUILD% /s /q 9 | mkdir %BUILD% 10 | cd %BUILD% 11 | 12 | 13 | rem -DXSI_VERSION="2014 SP2" ^ 14 | rem -DXSI_VERSION="2015" ^ 15 | 16 | cmake ^ 17 | -DTARGET_DCC=XSI ^ 18 | -DXSI_VERSION="2015" ^ 19 | -G "%COMPILER%" ..\ 20 | 21 | cmake --build . --config Release --target INSTALL 22 | 23 | pause 24 | --------------------------------------------------------------------------------