├── GL_Extensions.h ├── Toe ├── BulletCHOP_setup.toe └── BulletCHOP_setup.3.toe ├── README.md ├── .gitattributes ├── license.txt ├── BulletCHOP.sln ├── .gitignore ├── BulletCHOP.h ├── BulletCHOP.vcxproj ├── CHOP_CPlusPlusBase.h ├── BulletCHOP.cpp └── CPlusPlus_Common.h /GL_Extensions.h: -------------------------------------------------------------------------------- 1 | // Stub file for simpler CHOP usage than an OpenGLTOP 2 | 3 | #include 4 | -------------------------------------------------------------------------------- /Toe/BulletCHOP_setup.toe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinz9/BulletCHOP/HEAD/Toe/BulletCHOP_setup.toe -------------------------------------------------------------------------------- /Toe/BulletCHOP_setup.3.toe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinz9/BulletCHOP/HEAD/Toe/BulletCHOP_setup.3.toe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BulletCHOP 2 | ========== 3 | 4 | Bullet Physics in Touch Designer as a Channel Operator. 5 | Requires Bullet Physics library (http://bulletphysics.org/) to compile. 6 | Tested with v2.87. 7 | 8 | 06/25/2018 v0.2 : update to Bullet 2.87 and TouchDesigner 099 9 | 04/08/2013 v0.1 : dynamic and kinematic bodies implemented, only box collision shape 10 | 11 | 12 | Vincent Houzé 13 | https://vincenthouze.com -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013 Vincent Houze 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. -------------------------------------------------------------------------------- /BulletCHOP.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BulletCHOP", "BulletCHOP.vcxproj", "{3F5BEECD-FA36-459F-91B8-BB481A67EF44}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|Win32.Build.0 = Debug|Win32 16 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|x64.ActiveCfg = Debug|x64 17 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|x64.Build.0 = Debug|x64 18 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|Win32.ActiveCfg = Release|Win32 19 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|Win32.Build.0 = Release|Win32 20 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|x64.ActiveCfg = Release|x64 21 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.obj 2 | *.idb 3 | *.pdb 4 | *.ncb 5 | *.dep 6 | *.manifest 7 | *.suo 8 | *.ilk 9 | *.vinz7* 10 | *.bak 11 | *.exp 12 | *.db 13 | *.exe 14 | VH*.lib 15 | BuildLog.htm 16 | 17 | ################# 18 | ## Eclipse 19 | ################# 20 | 21 | *.pydevproject 22 | .project 23 | .metadata 24 | bin/ 25 | tmp/ 26 | *.tmp 27 | *.bak 28 | *.swp 29 | *~.nib 30 | local.properties 31 | .classpath 32 | .settings/ 33 | .loadpath 34 | 35 | # External tool builders 36 | .externalToolBuilders/ 37 | 38 | # Locally stored "Eclipse launch configurations" 39 | *.launch 40 | 41 | # CDT-specific 42 | .cproject 43 | 44 | # PDT-specific 45 | .buildpath 46 | 47 | 48 | ################# 49 | ## Visual Studio 50 | ################# 51 | 52 | ## Ignore Visual Studio temporary files, build results, and 53 | ## files generated by popular Visual Studio add-ons. 54 | 55 | # User-specific files 56 | *.suo 57 | *.user 58 | *.sln.docstates 59 | 60 | # Build results 61 | [Dd]ebug/ 62 | [Rr]elease/ 63 | *_i.c 64 | *_p.c 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.pch 69 | *.pdb 70 | *.pgc 71 | *.pgd 72 | *.rsp 73 | *.sbr 74 | *.tlb 75 | *.tli 76 | *.tlh 77 | *.tmp 78 | *.vspscc 79 | .builds 80 | *.dotCover 81 | 82 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 83 | #packages/ 84 | 85 | # Visual C++ cache files 86 | ipch/ 87 | *.aps 88 | *.ncb 89 | *.opensdf 90 | *.sdf 91 | 92 | # Visual Studio profiler 93 | *.psess 94 | *.vsp 95 | 96 | # ReSharper is a .NET coding add-in 97 | _ReSharper* 98 | 99 | # Installshield output folder 100 | [Ee]xpress 101 | 102 | # DocProject is a documentation generator add-in 103 | DocProject/buildhelp/ 104 | DocProject/Help/*.HxT 105 | DocProject/Help/*.HxC 106 | DocProject/Help/*.hhc 107 | DocProject/Help/*.hhk 108 | DocProject/Help/*.hhp 109 | DocProject/Help/Html2 110 | DocProject/Help/html 111 | 112 | # Click-Once directory 113 | publish 114 | 115 | # Others 116 | [Bb]in 117 | [Oo]bj 118 | sql 119 | TestResults 120 | *.Cache 121 | ClientBin 122 | stylecop.* 123 | ~$* 124 | *.dbmdl 125 | Generated_Code #added for RIA/Silverlight projects 126 | 127 | # Backup & report files from converting an old project file to a newer 128 | # Visual Studio version. Backup files are not needed, because we have git ;-) 129 | _UpgradeReport_Files/ 130 | Backup*/ 131 | UpgradeLog*.XML 132 | 133 | 134 | 135 | ############ 136 | ## Windows 137 | ############ 138 | 139 | # Windows image file caches 140 | Thumbs.db 141 | 142 | # Folder config file 143 | Desktop.ini 144 | 145 | 146 | ############# 147 | ## Python 148 | ############# 149 | 150 | *.py[co] 151 | 152 | # Packages 153 | *.egg 154 | *.egg-info 155 | dist 156 | build 157 | eggs 158 | parts 159 | bin 160 | var 161 | sdist 162 | develop-eggs 163 | .installed.cfg 164 | 165 | # Installer logs 166 | pip-log.txt 167 | 168 | # Unit test / coverage reports 169 | .coverage 170 | .tox 171 | 172 | #Translations 173 | *.mo 174 | 175 | #Mr Developer 176 | .mr.developer.cfg 177 | 178 | # Mac crap 179 | .DS_Store 180 | -------------------------------------------------------------------------------- /BulletCHOP.h: -------------------------------------------------------------------------------- 1 | #include "CHOP_CPlusPlusBase.h" 2 | 3 | #include 4 | 5 | 6 | 7 | // To get more help about these functions, look at CHOP_CPlusPlusBase.h 8 | 9 | 10 | class BulletCHOP : public CHOP_CPlusPlusBase 11 | { 12 | public: 13 | BulletCHOP(const OP_NodeInfo *info); 14 | virtual ~BulletCHOP(); 15 | 16 | virtual void getGeneralInfo(CHOP_GeneralInfo*) override; 17 | virtual bool getOutputInfo(CHOP_OutputInfo*) override; 18 | virtual const char* getChannelName(int index, void* reserved) override; 19 | 20 | virtual void execute(const CHOP_Output*, 21 | OP_Inputs*, 22 | void* reserved) override; 23 | 24 | 25 | virtual int getNumInfoCHOPChans() override; 26 | virtual void getInfoCHOPChan(int index, 27 | OP_InfoCHOPChan* chan) override; 28 | 29 | virtual bool getInfoDATSize(OP_InfoDATSize* infoSize) override; 30 | virtual void getInfoDATEntries(int index, 31 | int nEntries, 32 | OP_InfoDATEntries* entries) override; 33 | 34 | virtual void setupParameters(OP_ParameterManager* manager) override; 35 | virtual void pulsePressed(const char* name) override; 36 | 37 | void worldSetup(); 38 | 39 | void worldDestroy(); 40 | 41 | void addRigidBox(btVector3 pos, btVector3 rot, btVector3 scale, btScalar mass); 42 | void addRigidSphere(btVector3 pos, btVector3 rot, btScalar radius, btScalar mass); 43 | void addKineBox(btVector3 pos, btVector3 rot, btVector3 scale); 44 | 45 | void addPlane(btVector3 planeNormal, btScalar planeConstant); 46 | 47 | void initRigidSpheres(OP_Inputs* inputs); 48 | void initRigidBoxes(OP_Inputs* inputs); 49 | void initKineBoxes(OP_Inputs* inputs); 50 | void initPlanes(OP_Inputs* inputs); 51 | void updateKineBoxes(OP_Inputs* inputs); 52 | 53 | void removeBodies(); 54 | 55 | btScalar getDeltaTimeMicroseconds() 56 | { 57 | btScalar dt = (btScalar)clock.getTimeMicroseconds(); 58 | clock.reset(); 59 | return dt; 60 | } 61 | 62 | private: 63 | 64 | // We don't need to store this pointer, but we do for the example. 65 | // The CHOP_NodeInfo class store information about the node that's using 66 | // this instance of the class (like its name). 67 | const OP_NodeInfo *myNodeInfo; 68 | 69 | // In this example this value will be incremented each time the execute() 70 | // function is called, then passes back to the CHOP 71 | int myExecuteCount; 72 | 73 | float pos; 74 | float ms; 75 | 76 | btBroadphaseInterface* broadphase; 77 | btDefaultCollisionConfiguration* collisionConfiguration; 78 | btCollisionDispatcher* dispatcher; 79 | btSequentialImpulseConstraintSolver* solver; 80 | btDiscreteDynamicsWorld* dynamicsWorld; 81 | 82 | btClock clock; 83 | 84 | btAlignedObjectArray rigidSpheresShapes; 85 | btAlignedObjectArray rigidBoxesShapes; 86 | btAlignedObjectArray kineBoxesShapes; 87 | btAlignedObjectArray staticPlanesShapes; 88 | 89 | 90 | btAlignedObjectArray rigidSpheresIds; 91 | btAlignedObjectArray rigidBoxesIds; 92 | btAlignedObjectArray kineBoxesIds; 93 | btAlignedObjectArray staticPlanesIds; 94 | 95 | enum { TX, TY, TZ, RX, RY, RZ , SPEED, QX, QY, QZ, QW}; 96 | 97 | 98 | int frame = 0; 99 | 100 | 101 | }; 102 | -------------------------------------------------------------------------------- /BulletCHOP.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {3F5BEECD-FA36-459F-91B8-BB481A67EF44} 23 | CPlusPlusCHOPExample 24 | Win32Proj 25 | 26 | 27 | 28 | DynamicLibrary 29 | NotSet 30 | true 31 | v140 32 | 33 | 34 | DynamicLibrary 35 | NotSet 36 | true 37 | v140 38 | 39 | 40 | DynamicLibrary 41 | NotSet 42 | v140 43 | 44 | 45 | DynamicLibrary 46 | NotSet 47 | v140 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | <_ProjectFileVersion>10.0.40219.1 67 | $(SolutionDir)\$(Platform)\$(Configuration)\ 68 | $(SolutionDir)\$(Platform)\$(Configuration)\ 69 | $(Configuration)\ 70 | $(Configuration)\ 71 | false 72 | false 73 | $(SolutionDir)\$(Platform)\$(Configuration)\ 74 | $(SolutionDir)\$(Platform)\$(Configuration)\ 75 | $(Configuration)\ 76 | $(Configuration)\ 77 | false 78 | false 79 | 80 | 81 | 82 | Disabled 83 | WIN32;_DEBUG;_WINDOWS;_USRDLL;CPLUSPLUSCHOPEXAMPLE_EXPORTS;%(PreprocessorDefinitions) 84 | true 85 | EnableFastChecks 86 | MultiThreadedDebugDLL 87 | 88 | 89 | Level3 90 | ProgramDatabase 91 | D:\Documents\Dev\bullet-2.81-rev2613\src 92 | 93 | 94 | true 95 | Windows 96 | MachineX86 97 | D:\Documents\Dev\bullet-2.81-rev2613\lib 98 | BulletCollision_vs2010_debug.lib;BulletDynamics_vs2010_debug.lib;LinearMath_vs2010_debug.lib;%(AdditionalDependencies) 99 | 100 | 101 | 102 | 103 | Disabled 104 | WIN32;_DEBUG;_WINDOWS;_USRDLL;CPLUSPLUSCHOPEXAMPLE_EXPORTS;%(PreprocessorDefinitions) 105 | EnableFastChecks 106 | MultiThreadedDebug 107 | 108 | 109 | Level3 110 | ProgramDatabase 111 | $(BULLET_PATH)\src 112 | 113 | 114 | true 115 | Windows 116 | $(BULLET_BUILD_X64_PATH)\Debug 117 | BulletCollision_Debug.lib;BulletDynamics_Debug.lib;LinearMath_Debug.lib;%(AdditionalDependencies) 118 | 119 | 120 | 121 | 122 | WIN32;NDEBUG;_WINDOWS;_USRDLL;CPLUSPLUSCHOPEXAMPLE_EXPORTS;%(PreprocessorDefinitions) 123 | MultiThreadedDLL 124 | 125 | 126 | Level3 127 | ProgramDatabase 128 | D:\Documents\Dev\bullet-2.81-rev2613\src 129 | 130 | 131 | true 132 | Windows 133 | true 134 | true 135 | MachineX86 136 | D:\Documents\Dev\bullet-2.81-rev2613\lib 137 | BulletCollision_vs2010.lib;BulletDynamics_vs2010.lib;LinearMath_vs2010.lib;%(AdditionalDependencies) 138 | 139 | 140 | 141 | 142 | WIN32;NDEBUG;_WINDOWS;_USRDLL;CPLUSPLUSCHOPEXAMPLE_EXPORTS;%(PreprocessorDefinitions) 143 | MultiThreaded 144 | 145 | 146 | Level3 147 | ProgramDatabase 148 | $(BULLET_PATH)\src 149 | 150 | 151 | true 152 | Windows 153 | true 154 | true 155 | BulletCollision.lib;BulletDynamics.lib;LinearMath.lib;%(AdditionalDependencies) 156 | $(BULLET_BUILD_X64_PATH)\Release 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /CHOP_CPlusPlusBase.h: -------------------------------------------------------------------------------- 1 | /* Shared Use License: This file is owned by Derivative Inc. (Derivative) and 2 | * can only be used, and/or modified for use, in conjunction with 3 | * Derivative's TouchDesigner software, and only if you are a licensee who has 4 | * accepted Derivative's TouchDesigner license or assignment agreement (which 5 | * also govern the use of this file). You may share a modified version of this 6 | * file with another authorized licensee of Derivative's TouchDesigner software. 7 | * Otherwise, no redistribution or sharing of this file, with or without 8 | * modification, is permitted. 9 | */ 10 | 11 | /* 12 | * Produced by: 13 | * 14 | * Derivative Inc 15 | * 401 Richmond Street West, Unit 386 16 | * Toronto, Ontario 17 | * Canada M5V 3A8 18 | * 416-591-3555 19 | * 20 | * NAME: CHOP_CPlusPlusBase.h 21 | * 22 | * 23 | * Do not edit this file directly! 24 | * Make a subclass of CHOP_CPlusPlusBase instead, and add your own 25 | * data/functions. 26 | 27 | * Derivative Developers:: Make sure the virtual function order 28 | * stays the same, otherwise changes won't be backwards compatible 29 | */ 30 | 31 | #ifndef __CHOP_CPlusPlusBase__ 32 | #define __CHOP_CPlusPlusBase__ 33 | 34 | #include "CPlusPlus_Common.h" 35 | 36 | #define CHOP_CPLUSPLUS_API_VERSION 6 37 | 38 | class CHOP_CPlusPlusBase; 39 | 40 | 41 | // These are the definitions for the C-functions that are used to 42 | // load the library and create instances of the object you define 43 | typedef int32_t (__cdecl *GETCHOPAPIVERSION)(void); 44 | typedef CHOP_CPlusPlusBase* (__cdecl *CREATECHOPINSTANCE)(const OP_NodeInfo*); 45 | typedef void (__cdecl *DESTROYCHOPINSTANCE)(CHOP_CPlusPlusBase*); 46 | 47 | 48 | class CHOP_GeneralInfo 49 | { 50 | public: 51 | // Set this to true if you want the CHOP to cook every frame, even 52 | // if none of it's inputs/parameters are changing 53 | // DEFAULT: false 54 | 55 | bool cookEveryFrame; 56 | 57 | // Set this to true if you want the CHOP to cook every frame, but only 58 | // if someone asks for it to cook. So if nobody is using the output from 59 | // the CHOP, it won't cook. This is difereent from 'cookEveryFrame' 60 | // since that will cause it to cook every frame no matter what. 61 | 62 | bool cookEveryFrameIfAsked; 63 | 64 | // Set this to true if you will be outputting a timeslice 65 | // Outputting a timeslice means the number of samples in the CHOP will 66 | // be determined by the number of frames that have elapsed since the last 67 | // time TouchDesigner cooked (it will be more than one in cases where it's 68 | // running slower than the target cook rate), the playbar framerate and 69 | // the sample rate of the CHOP. 70 | // For example if you are outputting the CHOP 120hz sample rate, 71 | // TouchDesigner is running at 60 hz cookrate, and you missed a frame last cook 72 | // then on this cook the number of sampels of the output of this CHOP will 73 | // be 4 samples. I.e (120 / 60) * number of playbar frames to output. 74 | // If this isn't set then you specify the number of sample in the CHOP using 75 | // the getOutputInfo() function 76 | // DEFAULT: false 77 | 78 | bool timeslice; 79 | 80 | // If you are returning 'false' from getOutputInfo, this index will 81 | // specify the CHOP input whos attribues you will match 82 | // (channel names, length, sample rate etc.) 83 | // DEFAULT : 0 84 | 85 | int32_t inputMatchIndex; 86 | 87 | 88 | private: 89 | int32_t reserved[20]; 90 | }; 91 | 92 | 93 | class CHOP_OutputInfo 94 | { 95 | public: 96 | 97 | // The number of channels you want to output 98 | 99 | int32_t numChannels; 100 | 101 | 102 | // If you arn't outputting a timeslice, specify the number of samples here 103 | 104 | int32_t numSamples; 105 | 106 | 107 | // if you arn't outputting a timeslice, specify the start index 108 | // of the channels here. This is the 'Start' you see when you 109 | // middle click on a CHOP 110 | 111 | uint32_t startIndex; 112 | 113 | 114 | // Specify the sample rate of the channel data 115 | // DEFAULT : whatever the timeline FPS is ($FPS) 116 | 117 | float sampleRate; 118 | 119 | 120 | // This is provided for you incase you want to use data from the 121 | // your inputs/parameters to decide what you will be outputting from 122 | // the CHOP, you shouldn't change anything in this structure 123 | 124 | OP_Inputs* opInputs; 125 | 126 | private: 127 | 128 | int32_t reserved[20]; 129 | 130 | }; 131 | 132 | 133 | 134 | class CHOP_Output 135 | { 136 | public: 137 | CHOP_Output(int32_t nc, int32_t l, float s, uint32_t st): 138 | numChannels(nc), 139 | numSamples(l), 140 | sampleRate(s), 141 | startIndex(st) 142 | { 143 | } 144 | 145 | // Info about what you are expected to output 146 | const int32_t numChannels; 147 | const int32_t numSamples; 148 | const float sampleRate; 149 | const uint32_t startIndex; 150 | 151 | // This is an array of const char* that tells you the channel names 152 | // of the channels you are providing values for. It's 'numChannels' long. 153 | // E.g names[3] is the name of the 4th channel 154 | const char** names; 155 | 156 | // This is an array of float arrays, the length of the array is 157 | // 'numChannels', while the length of each of the arrays each entry 158 | // points to is 'numSamples'. 159 | // For example channels[1][10] will point to the 11th sample in the 2nd 160 | // channel 161 | float** channels; 162 | 163 | 164 | private: 165 | 166 | int32_t reserved[20]; 167 | }; 168 | 169 | 170 | /***** FUNCTION CALL ORDER DURING INITIALIZATION ******/ 171 | /* 172 | When the TOP loads the dll the functions will be called in this order 173 | 174 | setupParameters(OP_ParameterManager* m); 175 | 176 | */ 177 | 178 | /***** FUNCTION CALL ORDER DURING A COOK ******/ 179 | /* 180 | 181 | When the CHOP cooks the functions will be called in this order 182 | 183 | getGeneralInfo() 184 | getOutputInfo() 185 | if getOutputInfo() returns true 186 | { 187 | getChannelName() once for each channel needed 188 | } 189 | execute() 190 | getNumInfoCHOPChans() 191 | for the number of chans returned getNumInfoCHOPChans() 192 | { 193 | getInfoCHOPChan() 194 | } 195 | getInfoDATSize() 196 | for the number of rows/cols returned by getInfoDATSize() 197 | { 198 | getInfoDATEntries() 199 | } 200 | getInfoPopupString() 201 | getWarningString() 202 | getErrorString() 203 | */ 204 | 205 | /*** DO NOT EDIT THIS CLASS, MAKE A SUBCLASS OF IT INSTEAD ***/ 206 | class CHOP_CPlusPlusBase 207 | { 208 | protected: 209 | CHOP_CPlusPlusBase() 210 | { 211 | } 212 | 213 | 214 | public: 215 | 216 | virtual ~CHOP_CPlusPlusBase() 217 | { 218 | } 219 | 220 | // BEGIN PUBLIC INTERFACE 221 | 222 | // Some general settings can be assigned here (if you ovierride it) 223 | 224 | virtual void getGeneralInfo(CHOP_GeneralInfo*) 225 | { 226 | } 227 | 228 | 229 | // This function is called so the class can tell the CHOP how many 230 | // channels it wants to output, how many samples etc. 231 | // Return true if you specify the output here 232 | // Return false if you want the output to be set by matching 233 | // the channel names, numSamples, sample rate etc. of one of your inputs 234 | // The input that is used is chosen by setting the 'inputMatchIndex' 235 | // memeber in getGeneralInfo() 236 | // The CHOP_OutputFormat class is pre-filled with what the CHOP would 237 | // output if you return false, so you can just tweak a few settings 238 | // and return true if you want 239 | 240 | virtual bool getOutputInfo(CHOP_OutputInfo*) 241 | { 242 | return false; 243 | } 244 | 245 | 246 | // This function will be called after getOutputInfo() asking for 247 | // the channel names. It will get called once for each channel name 248 | // you need to specify. If you returned 'false' from getOutputInfo() 249 | // it won't be called. 250 | 251 | virtual const char* getChannelName(int32_t index, void* reserved) 252 | { 253 | return "chan1"; 254 | } 255 | 256 | 257 | // In this function you do whatever you want to fill the framebuffer 258 | // 259 | // See the OP_Inputs class definition for more details on it's 260 | // contents 261 | 262 | virtual void execute(const CHOP_Output*, 263 | OP_Inputs* , 264 | void* reserved) = 0; 265 | 266 | 267 | // Override these methods if you want to output values to the Info CHOP/DAT 268 | // returning 0 means you dont plan to output any Info CHOP channels 269 | 270 | virtual int32_t getNumInfoCHOPChans() 271 | { 272 | return 0; 273 | } 274 | 275 | // Specify the name and value for CHOP 'index', 276 | // by assigning something to 'name' and 'value' members of the 277 | // CHOP_InfoCHOPChan class pointer that is passed (it points 278 | // to a valid instance of the class already. 279 | // the 'name' pointer will initially point to nullptr 280 | // you must allocate memory or assign a constant string 281 | // to it. 282 | 283 | virtual void getInfoCHOPChan(int32_t index, 284 | OP_InfoCHOPChan* chan) 285 | { 286 | } 287 | 288 | 289 | // Return false if you arn't returning data for an Info DAT 290 | // Return true if you are. 291 | // Set the members of the CHOP_InfoDATSize class to specify 292 | // the dimensions of the Info DAT 293 | 294 | virtual bool getInfoDATSize(OP_InfoDATSize* infoSize) 295 | { 296 | return false; 297 | } 298 | 299 | // You are asked to assign values to the Info DAT 1 row or column at a time 300 | // The 'byColumn' variable in 'getInfoDATSize' is how you specify 301 | // if it is by column or by row. 302 | // 'index' is the row/column index 303 | // 'nEntries' is the number of entries in the row/column 304 | 305 | virtual void getInfoDATEntries(int32_t index, 306 | int32_t nEntries, 307 | OP_InfoDATEntries* entries) 308 | { 309 | } 310 | 311 | // You can use this function to put the node into a warning state 312 | // with the returned string as the message. 313 | // Return nullptr if you don't want it to be in a warning state. 314 | virtual const char* getWarningString() 315 | { 316 | return nullptr; 317 | } 318 | 319 | // You can use this function to put the node into a error state 320 | // with the returned string as the message. 321 | // Return nullptr if you don't want it to be in a error state. 322 | virtual const char* getErrorString() 323 | { 324 | return nullptr; 325 | } 326 | 327 | // Use this function to return some text that will show up in the 328 | // info popup (when you middle click on a node) 329 | // Return nullptr if you don't want to return anything. 330 | virtual const char* getInfoPopupString() 331 | { 332 | return nullptr; 333 | } 334 | 335 | 336 | // Override these methods if you want to define specfic parameters 337 | virtual void setupParameters(OP_ParameterManager* manager) 338 | { 339 | } 340 | 341 | 342 | // This is called whenever a pulse parameter is pressed 343 | virtual void pulsePressed(const char* name) 344 | { 345 | } 346 | 347 | // END PUBLIC INTERFACE 348 | 349 | 350 | private: 351 | 352 | // Reserved for future features 353 | virtual int32_t reservedFunc6() { return 0; } 354 | virtual int32_t reservedFunc7() { return 0; } 355 | virtual int32_t reservedFunc8() { return 0; } 356 | virtual int32_t reservedFunc9() { return 0; } 357 | virtual int32_t reservedFunc10() { return 0; } 358 | virtual int32_t reservedFunc11() { return 0; } 359 | virtual int32_t reservedFunc12() { return 0; } 360 | virtual int32_t reservedFunc13() { return 0; } 361 | virtual int32_t reservedFunc14() { return 0; } 362 | virtual int32_t reservedFunc15() { return 0; } 363 | virtual int32_t reservedFunc16() { return 0; } 364 | virtual int32_t reservedFunc17() { return 0; } 365 | virtual int32_t reservedFunc18() { return 0; } 366 | virtual int32_t reservedFunc19() { return 0; } 367 | virtual int32_t reservedFunc20() { return 0; } 368 | 369 | int32_t reserved[400]; 370 | 371 | }; 372 | 373 | #endif 374 | -------------------------------------------------------------------------------- /BulletCHOP.cpp: -------------------------------------------------------------------------------- 1 | #include "BulletCHOP.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // These functions are basic C function, which the DLL loader can find 9 | // much easier than finding a C++ Class. 10 | // The DLLEXPORT prefix is needed so the compile exports these functions from the .dll 11 | // you are creating 12 | extern "C" 13 | { 14 | 15 | DLLEXPORT 16 | int 17 | GetCHOPAPIVersion(void) 18 | { 19 | // Always return CHOP_CPLUSPLUS_API_VERSION in this function. 20 | return CHOP_CPLUSPLUS_API_VERSION; 21 | } 22 | 23 | DLLEXPORT 24 | CHOP_CPlusPlusBase* 25 | CreateCHOPInstance(const OP_NodeInfo *info) 26 | { 27 | // Return a new instance of your class every time this is called. 28 | // It will be called once per CHOP that is using the .dll 29 | return new BulletCHOP(info); 30 | } 31 | 32 | DLLEXPORT 33 | void 34 | DestroyCHOPInstance(CHOP_CPlusPlusBase *instance) 35 | { 36 | // Delete the instance here, this will be called when 37 | // Touch is shutting down, when the CHOP using that instance is deleted, or 38 | // if the CHOP loads a different DLL 39 | delete (BulletCHOP*)instance; 40 | } 41 | 42 | }; 43 | 44 | 45 | BulletCHOP::BulletCHOP(const OP_NodeInfo *info) : myNodeInfo(info) 46 | { 47 | myExecuteCount = 0; 48 | pos = 0; 49 | ms = 0; 50 | 51 | worldSetup(); 52 | 53 | } 54 | 55 | BulletCHOP::~BulletCHOP() 56 | { 57 | 58 | worldDestroy(); 59 | 60 | } 61 | 62 | 63 | void BulletCHOP::worldSetup(){ 64 | 65 | collisionConfiguration = new btDefaultCollisionConfiguration; 66 | dispatcher = new btCollisionDispatcher(collisionConfiguration); 67 | solver = new btSequentialImpulseConstraintSolver; 68 | 69 | broadphase = new btDbvtBroadphase(); 70 | 71 | dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration); 72 | 73 | dynamicsWorld->setGravity(btVector3(0,-10,0)); 74 | 75 | btContactSolverInfo& info = dynamicsWorld->getSolverInfo(); 76 | info.m_splitImpulse = 1; 77 | info.m_splitImpulsePenetrationThreshold = -0.02; 78 | 79 | rigidBoxesShapes.resize(0); 80 | rigidSpheresShapes.resize(0); 81 | kineBoxesShapes.resize(0); 82 | staticPlanesShapes.resize(0); 83 | 84 | rigidBoxesIds.resize(0); 85 | rigidSpheresIds.resize(0); 86 | kineBoxesIds.resize(0); 87 | 88 | } 89 | 90 | void BulletCHOP::worldDestroy(){ 91 | 92 | removeBodies(); 93 | 94 | delete dynamicsWorld; 95 | delete solver; 96 | delete broadphase; 97 | delete dispatcher; 98 | delete collisionConfiguration; 99 | } 100 | 101 | void 102 | BulletCHOP::getGeneralInfo(CHOP_GeneralInfo *ginfo) 103 | { 104 | // This will cause the node to cook every frame 105 | ginfo->cookEveryFrameIfAsked = true; 106 | ginfo->timeslice = false; 107 | //ginfo->inputMatchIndex = 0; 108 | } 109 | 110 | bool 111 | BulletCHOP::getOutputInfo(CHOP_OutputInfo *info) 112 | { 113 | 114 | info->numChannels = 11; 115 | info->sampleRate = 60; 116 | 117 | if (rigidBoxesIds.size()>0) 118 | { 119 | info->numSamples = rigidBoxesIds.size(); 120 | } 121 | else 122 | { 123 | info->numSamples = 1; 124 | } 125 | 126 | return true; 127 | } 128 | 129 | const char* 130 | BulletCHOP::getChannelName(int index, void* reserved) 131 | { 132 | const char* name = ""; 133 | 134 | switch (index) { 135 | case TX: 136 | name = "tx"; 137 | break; 138 | case TY: 139 | name = "ty"; 140 | break; 141 | case TZ: 142 | name = "tz"; 143 | break; 144 | case RX: 145 | name = "rx"; 146 | break; 147 | case RY: 148 | name = "ry"; 149 | break; 150 | case RZ: 151 | name = "rz"; 152 | break; 153 | case SPEED: 154 | name = "speed"; 155 | break; 156 | case QX: 157 | name = "qx"; 158 | break; 159 | case QY: 160 | name = "qy"; 161 | break; 162 | case QZ: 163 | name = "qz"; 164 | break; 165 | case QW: 166 | name = "qw"; 167 | break; 168 | 169 | } 170 | 171 | return name; 172 | } 173 | 174 | /*void BulletCHOP::addBody(btVector3 pos, btVector3 rot, btVector3 scale, btScalar mass){ 175 | 176 | btCollisionShape* colShape = new btBoxShape(0.5*scale); 177 | 178 | //btCollisionShape* colShape = new btSphereShape(0.5*scale.getX()); 179 | 180 | collisionShapes.push_back(colShape); 181 | 182 | /// Create Dynamic Objects 183 | btTransform startTransform; 184 | startTransform.setIdentity(); 185 | 186 | //rigidbody is dynamic if and only if mass is non zero, otherwise static 187 | bool isDynamic = (mass != 0.f); 188 | 189 | btVector3 localInertia(0,0,0); 190 | if (isDynamic) 191 | colShape->calculateLocalInertia(mass,localInertia); 192 | 193 | btMatrix3x3 rotMat; 194 | rotMat.setEulerZYX(rot.x(),rot.y(),rot.z()); 195 | 196 | startTransform.setOrigin(pos); 197 | startTransform.setBasis(rotMat); 198 | 199 | 200 | //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects 201 | btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); 202 | btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia); 203 | btRigidBody* body = new btRigidBody(rbInfo); 204 | 205 | if(isDynamic == 0){ 206 | body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); 207 | body->setActivationState(DISABLE_DEACTIVATION); 208 | } 209 | 210 | dynamicsWorld->addRigidBody(body); 211 | 212 | }*/ 213 | 214 | void BulletCHOP::addKineBox(btVector3 pos, btVector3 rot, btVector3 scale) { 215 | 216 | btCollisionShape* colShape = new btBoxShape(0.5*scale); 217 | 218 | kineBoxesShapes.push_back(colShape); 219 | 220 | /// Create Dynamic Objects 221 | btTransform startTransform; 222 | startTransform.setIdentity(); 223 | 224 | btVector3 localInertia(0, 0, 0); 225 | 226 | btMatrix3x3 rotMat; 227 | rotMat.setEulerZYX(rot.x(), rot.y(), rot.z()); 228 | 229 | startTransform.setOrigin(pos); 230 | startTransform.setBasis(rotMat); 231 | 232 | //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects 233 | btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); 234 | btRigidBody::btRigidBodyConstructionInfo rbInfo(0, myMotionState, colShape, localInertia); 235 | 236 | btRigidBody* body = new btRigidBody(rbInfo); 237 | 238 | body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); 239 | body->setActivationState(DISABLE_DEACTIVATION); 240 | 241 | kineBoxesIds.push_back(dynamicsWorld->getCollisionObjectArray().size()); 242 | 243 | dynamicsWorld->addRigidBody(body); 244 | 245 | } 246 | 247 | void BulletCHOP::addRigidSphere(btVector3 pos, btVector3 rot, btScalar radius, btScalar mass) { 248 | 249 | btCollisionShape* colShape = new btSphereShape(radius); 250 | 251 | rigidSpheresShapes.push_back(colShape); 252 | 253 | /// Create Dynamic Objects 254 | btTransform startTransform; 255 | startTransform.setIdentity(); 256 | 257 | btVector3 localInertia(0, 0, 0); 258 | 259 | colShape->calculateLocalInertia(mass, localInertia); 260 | 261 | btMatrix3x3 rotMat; 262 | rotMat.setEulerZYX(rot.x(), rot.y(), rot.z()); 263 | 264 | startTransform.setOrigin(pos); 265 | startTransform.setBasis(rotMat); 266 | 267 | 268 | //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects 269 | btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); 270 | btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, colShape, localInertia); 271 | 272 | btRigidBody* body = new btRigidBody(rbInfo); 273 | 274 | rigidSpheresIds.push_back(dynamicsWorld->getCollisionObjectArray().size()); 275 | 276 | dynamicsWorld->addRigidBody(body); 277 | 278 | } 279 | 280 | void BulletCHOP::addRigidBox(btVector3 pos, btVector3 rot, btVector3 scale, btScalar mass) { 281 | 282 | btCollisionShape* colShape = new btBoxShape(0.5*scale); 283 | 284 | rigidBoxesShapes.push_back(colShape); 285 | 286 | /// Create Dynamic Objects 287 | btTransform startTransform; 288 | startTransform.setIdentity(); 289 | 290 | btVector3 localInertia(0, 0, 0); 291 | 292 | colShape->calculateLocalInertia(mass, localInertia); 293 | 294 | btMatrix3x3 rotMat; 295 | rotMat.setEulerZYX(rot.x(), rot.y(), rot.z()); 296 | 297 | startTransform.setOrigin(pos); 298 | startTransform.setBasis(rotMat); 299 | 300 | 301 | //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects 302 | btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); 303 | btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, colShape, localInertia); 304 | 305 | btRigidBody* body = new btRigidBody(rbInfo); 306 | 307 | rigidBoxesIds.push_back(dynamicsWorld->getCollisionObjectArray().size()); 308 | 309 | dynamicsWorld->addRigidBody(body); 310 | 311 | } 312 | 313 | void BulletCHOP::addPlane(btVector3 planeNormal, btScalar planeConstant){ 314 | 315 | 316 | btCollisionShape* groundShape = new btStaticPlaneShape(planeNormal, planeConstant); 317 | 318 | staticPlanesShapes.push_back(groundShape); 319 | 320 | btTransform groundTransform; 321 | groundTransform.setIdentity(); 322 | //groundTransform.setOrigin(pos); 323 | //groundTransform.setOrigin(btVector3(0,-50,0)); 324 | 325 | 326 | btScalar mass(0.); 327 | 328 | //rigidbody is dynamic if and only if mass is non zero, otherwise static 329 | 330 | btVector3 localInertia(0,0,0); 331 | 332 | //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects 333 | btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); 334 | btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); 335 | btRigidBody* body = new btRigidBody(rbInfo); 336 | 337 | //add the body to the dynamics world 338 | dynamicsWorld->addRigidBody(body); 339 | 340 | 341 | } 342 | 343 | void BulletCHOP::removeBodies(){ 344 | int i; 345 | for (i=dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) 346 | { 347 | btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[i]; 348 | btRigidBody* body = btRigidBody::upcast(obj); 349 | if (body && body->getMotionState()) 350 | { 351 | delete body->getMotionState(); 352 | } 353 | dynamicsWorld->removeCollisionObject( obj ); 354 | delete obj; 355 | } 356 | 357 | //delete collision shapes 358 | for (int j=0;jgetParCHOP("Spheresrigidchop")) { 387 | 388 | const OP_CHOPInput* spheresRigidInput = inputs->getParCHOP("Spheresrigidchop"); 389 | 390 | for (int i = 0; i < spheresRigidInput->numSamples; i++) { 391 | 392 | btVector3 pos = btVector3( 393 | spheresRigidInput->getChannelData(0)[i], 394 | spheresRigidInput->getChannelData(1)[i], 395 | spheresRigidInput->getChannelData(2)[i]); 396 | 397 | btVector3 rot = 0.017453*btVector3( 398 | spheresRigidInput->getChannelData(3)[i], 399 | spheresRigidInput->getChannelData(4)[i], 400 | spheresRigidInput->getChannelData(5)[i]); 401 | 402 | btScalar radius = spheresRigidInput->getChannelData(6)[i]; 403 | 404 | addRigidSphere(pos, rot, radius, 1); 405 | } 406 | } 407 | } 408 | 409 | void BulletCHOP::initRigidBoxes(OP_Inputs* inputs) { 410 | 411 | if (inputs->getParCHOP("Boxesrigidchop")) { 412 | const OP_CHOPInput* boxesRigidInput = inputs->getParCHOP("Boxesrigidchop"); 413 | 414 | for (int i = 0; i < boxesRigidInput->numSamples; i++) { 415 | 416 | btVector3 pos = btVector3( 417 | boxesRigidInput->getChannelData(0)[i], 418 | boxesRigidInput->getChannelData(1)[i], 419 | boxesRigidInput->getChannelData(2)[i]); 420 | 421 | btVector3 rot = 0.017453*btVector3( 422 | boxesRigidInput->getChannelData(3)[i], 423 | boxesRigidInput->getChannelData(4)[i], 424 | boxesRigidInput->getChannelData(5)[i]); 425 | 426 | btVector3 scale = btVector3( 427 | boxesRigidInput->getChannelData(6)[i], 428 | boxesRigidInput->getChannelData(7)[i], 429 | boxesRigidInput->getChannelData(8)[i]); 430 | 431 | addRigidBox(pos, rot, scale, 1); 432 | } 433 | } 434 | } 435 | 436 | 437 | void BulletCHOP::initKineBoxes(OP_Inputs* inputs) { 438 | 439 | if (inputs->getParCHOP("Boxeskinechop")) { 440 | const OP_CHOPInput* boxesKineInput = inputs->getParCHOP("Boxeskinechop"); 441 | 442 | for (int i = 0; i < boxesKineInput->numSamples; i++) { 443 | 444 | btVector3 pos = btVector3( 445 | boxesKineInput->getChannelData(0)[i], 446 | boxesKineInput->getChannelData(1)[i], 447 | boxesKineInput->getChannelData(2)[i]); 448 | 449 | btVector3 rot = 0.017453*btVector3( 450 | boxesKineInput->getChannelData(3)[i], 451 | boxesKineInput->getChannelData(4)[i], 452 | boxesKineInput->getChannelData(5)[i]); 453 | 454 | btVector3 scale = btVector3( 455 | boxesKineInput->getChannelData(6)[i], 456 | boxesKineInput->getChannelData(7)[i], 457 | boxesKineInput->getChannelData(8)[i]); 458 | 459 | addKineBox(pos, rot, scale); 460 | } 461 | } 462 | } 463 | 464 | void BulletCHOP::updateKineBoxes(OP_Inputs* inputs) { 465 | 466 | if (inputs->getParCHOP("Boxeskinechop") && kineBoxesIds.size()>0) { 467 | 468 | const OP_CHOPInput* boxesKineInput = inputs->getParCHOP("Boxeskinechop"); 469 | 470 | for (int i = 0; i < boxesKineInput->numSamples; i++) { 471 | 472 | int index = kineBoxesIds[i]; 473 | 474 | btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[index]; 475 | btRigidBody* body = btRigidBody::upcast(obj); 476 | 477 | btVector3 pos = btVector3( 478 | boxesKineInput->getChannelData(0)[i], 479 | boxesKineInput->getChannelData(1)[i], 480 | boxesKineInput->getChannelData(2)[i]); 481 | 482 | btVector3 rot = 0.017453*btVector3( 483 | boxesKineInput->getChannelData(3)[i], 484 | boxesKineInput->getChannelData(4)[i], 485 | boxesKineInput->getChannelData(5)[i]); 486 | 487 | btTransform trans; 488 | 489 | trans.setOrigin(pos); 490 | 491 | btMatrix3x3 rotMat; 492 | rotMat.setEulerZYX(rot.x(), rot.y(), rot.z()); 493 | 494 | trans.setBasis(rotMat); 495 | 496 | body->getMotionState()->setWorldTransform(trans); 497 | } 498 | } 499 | } 500 | 501 | void BulletCHOP::initPlanes(OP_Inputs* inputs) { 502 | 503 | if (inputs->getParCHOP("Colplaneschop")) { 504 | 505 | const OP_CHOPInput* colPlanesInput = inputs->getParCHOP("Colplaneschop"); 506 | 507 | for (int i = 0; i < colPlanesInput->numSamples; i++) { 508 | 509 | btVector3 pos = btVector3( 510 | colPlanesInput->getChannelData(0)[i], 511 | colPlanesInput->getChannelData(1)[i], 512 | colPlanesInput->getChannelData(2)[i]); 513 | 514 | } 515 | } 516 | } 517 | 518 | 519 | void BulletCHOP::execute(const CHOP_Output* output, 520 | OP_Inputs* inputs, 521 | void* reserved) 522 | { 523 | myExecuteCount++; 524 | 525 | double gravity[3]; 526 | inputs->getParDouble3("Gravity", gravity[0], gravity[1], gravity[2]); 527 | 528 | dynamicsWorld->setGravity(btVector3(gravity[0], gravity[1], gravity[2])); 529 | 530 | int reset = inputs->getParInt("Reset"); 531 | 532 | if (reset == 1) { 533 | 534 | removeBodies(); 535 | 536 | frame = 0; 537 | 538 | //initRigidSpheres(inputs); 539 | initRigidBoxes(inputs); 540 | 541 | initKineBoxes(inputs); 542 | 543 | } 544 | 545 | else 546 | 547 | { 548 | 549 | updateKineBoxes(inputs); 550 | 551 | ms = getDeltaTimeMicroseconds() / 1000000.f; 552 | 553 | /*float maxSubsteps = float(inputs->getParInt("Maxsubsteps")); 554 | float fps = float(inputs->getParInt("Fps")); 555 | dynamicsWorld->stepSimulation(ms, maxSubsteps, 1.f / fps);*/ 556 | 557 | float substeps = float(inputs->getParInt("Substeps")); 558 | float fps = float(inputs->getParInt("Fps")); 559 | 560 | btScalar elapsedTime = 1.0 / fps; 561 | btScalar fixedTimestep = elapsedTime / substeps; 562 | 563 | dynamicsWorld->stepSimulation(elapsedTime, int(substeps + 1), fixedTimestep); 564 | 565 | int iterations = inputs->getParInt("Iterations"); 566 | dynamicsWorld->getSolverInfo().m_numIterations = iterations; 567 | 568 | for (int i = 0; i < rigidBoxesIds.size(); i++){ 569 | 570 | int index = rigidBoxesIds[i]; 571 | 572 | btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[index]; 573 | btRigidBody* body = btRigidBody::upcast(obj); 574 | 575 | btTransform trans; 576 | body->getMotionState()->getWorldTransform(trans); 577 | 578 | output->channels[TX][i] = float(trans.getOrigin().getX()); 579 | output->channels[TY][i] = float(trans.getOrigin().getY()); 580 | output->channels[TZ][i] = float(trans.getOrigin().getZ()); 581 | 582 | btScalar rotX, rotY, rotZ; 583 | 584 | //caution about X and Z 585 | trans.getBasis().getEulerZYX(rotZ,rotY,rotX); 586 | 587 | output->channels[RX][i] = float(rotX)*57.2958; 588 | output->channels[RY][i] = float(rotY)*57.2958; 589 | output->channels[RZ][i] = float(rotZ)*57.2958; 590 | 591 | btVector3 vel = body->getLinearVelocity(); 592 | 593 | output->channels[SPEED][i] = pow(vel.x(),2)+pow(vel.y(),2)+pow(vel.z(),2); 594 | 595 | btQuaternion rot = trans.getRotation(); 596 | 597 | output->channels[QX][index] = float(rot.x()); 598 | output->channels[QY][index] = float(rot.y()); 599 | output->channels[QZ][index] = float(rot.z()); 600 | output->channels[QW][index] = float(rot.w()); 601 | 602 | } 603 | 604 | } 605 | 606 | } 607 | 608 | int 609 | BulletCHOP::getNumInfoCHOPChans() 610 | { 611 | // We return the number of channel we want to output to any Info CHOP 612 | // connected to the CHOP. In this example we are just going to send one channel. 613 | return 2; 614 | } 615 | 616 | void 617 | BulletCHOP::getInfoCHOPChan(int index, OP_InfoCHOPChan* chan) 618 | { 619 | // This function will be called once for each channel we said we'd want to return 620 | // In this example it'll only be called once. 621 | 622 | if (index == 0) 623 | { 624 | chan->name = "executeCount"; 625 | chan->value = myExecuteCount; 626 | } 627 | 628 | if (index == 1) 629 | { 630 | chan->name = "ms"; 631 | chan->value = ms; 632 | } 633 | } 634 | 635 | bool 636 | BulletCHOP::getInfoDATSize(OP_InfoDATSize *infoSize) 637 | { 638 | infoSize->rows = 2; 639 | infoSize->cols = 2; 640 | // Setting this to false means we'll be assigning values to the table 641 | // one row at a time. True means we'll do it one column at a time. 642 | infoSize->byColumn = false; 643 | return true; 644 | } 645 | 646 | void 647 | BulletCHOP::getInfoDATEntries(int index, 648 | int nEntries, 649 | OP_InfoDATEntries *entries) 650 | { 651 | if (index == 0) 652 | { 653 | // It's safe to use static buffers here because Touch will make it's own 654 | // copies of the strings immediately after this call returns 655 | // (so the buffers can be reuse for each column/row) 656 | static char tempBuffer1[4096]; 657 | static char tempBuffer2[4096]; 658 | // Set the value for the first column 659 | strcpy(tempBuffer1, "executeCount"); 660 | entries->values[0] = tempBuffer1; 661 | 662 | // Set the value for the second column 663 | sprintf(tempBuffer2, "%d", myExecuteCount); 664 | entries->values[1] = tempBuffer2; 665 | 666 | 667 | } 668 | 669 | if (index == 1) 670 | { 671 | // It's safe to use static buffers here because Touch will make it's own 672 | // copies of the strings immediately after this call returns 673 | // (so the buffers can be reuse for each column/row) 674 | static char tempBuffer1[4096]; 675 | static char tempBuffer2[4096]; 676 | // Set the value for the first column 677 | strcpy(tempBuffer1, "ms"); 678 | entries->values[0] = tempBuffer1; 679 | 680 | // Set the value for the second column 681 | sprintf(tempBuffer2, "%f", ms); 682 | entries->values[1] = tempBuffer2; 683 | 684 | 685 | } 686 | } 687 | 688 | void BulletCHOP::setupParameters(OP_ParameterManager* manager) 689 | { 690 | 691 | // Reset 692 | { 693 | OP_NumericParameter np; 694 | 695 | np.name = "Reset"; 696 | np.label = "Reset"; 697 | np.defaultValues[0] = 0.0; 698 | 699 | OP_ParAppendResult res = manager->appendInt(np); 700 | assert(res == OP_ParAppendResult::Success); 701 | } 702 | 703 | 704 | // Maxsubsteps 705 | /*{ 706 | OP_NumericParameter np; 707 | 708 | np.name = "Maxsubsteps"; 709 | np.label = "Max Substeps"; 710 | //np.page = "Solver"; 711 | np.defaultValues[0] = 10; 712 | 713 | OP_ParAppendResult res = manager->appendInt(np); 714 | assert(res == OP_ParAppendResult::Success); 715 | }*/ 716 | 717 | // Fps 718 | { 719 | OP_NumericParameter np; 720 | 721 | np.name = "Fps"; 722 | np.label = "FPS"; 723 | //np.page = "Solver"; 724 | np.defaultValues[0] = 60; 725 | 726 | OP_ParAppendResult res = manager->appendFloat(np); 727 | assert(res == OP_ParAppendResult::Success); 728 | } 729 | 730 | // Substeps 731 | { 732 | OP_NumericParameter np; 733 | 734 | np.name = "Substeps"; 735 | np.label = "Substeps"; 736 | //np.page = "Solver"; 737 | np.defaultValues[0] = 1; 738 | 739 | 740 | OP_ParAppendResult res = manager->appendInt(np); 741 | assert(res == OP_ParAppendResult::Success); 742 | } 743 | 744 | // Iterations 745 | { 746 | OP_NumericParameter np; 747 | 748 | np.name = "Iterations"; 749 | np.label = "Iterations"; 750 | //np.page = "Solver"; 751 | np.defaultValues[0] = 10; 752 | 753 | OP_ParAppendResult res = manager->appendInt(np); 754 | assert(res == OP_ParAppendResult::Success); 755 | } 756 | 757 | //Gravity 758 | { 759 | OP_NumericParameter np; 760 | 761 | np.name = "Gravity"; 762 | np.label = "Gravity"; 763 | 764 | np.defaultValues[0] = 0.0; 765 | np.defaultValues[1] = -9.8; 766 | np.defaultValues[2] = 0.0; 767 | 768 | 769 | OP_ParAppendResult res = manager->appendXYZ(np); 770 | assert(res == OP_ParAppendResult::Success); 771 | } 772 | 773 | 774 | //Spheresrigidbodieschop 775 | /*{ 776 | OP_StringParameter sp; 777 | 778 | sp.name = "Spheresrigidchop"; 779 | sp.label = "Spheres Rigid Bodies CHOP"; 780 | //sp.page = "Collisions"; 781 | 782 | OP_ParAppendResult res = manager->appendCHOP(sp); 783 | assert(res == OP_ParAppendResult::Success); 784 | }*/ 785 | 786 | //Boxesrigidchop 787 | { 788 | OP_StringParameter sp; 789 | 790 | sp.name = "Boxesrigidchop"; 791 | sp.label = "Boxes Rigid Bodies CHOP"; 792 | //sp.page = "Collisions"; 793 | 794 | OP_ParAppendResult res = manager->appendCHOP(sp); 795 | assert(res == OP_ParAppendResult::Success); 796 | } 797 | 798 | //Boxeskinebodieschop 799 | { 800 | OP_StringParameter sp; 801 | 802 | sp.name = "Boxeskinechop"; 803 | sp.label = "Boxes Kinematic Bodies CHOP"; 804 | //sp.page = "Collisions"; 805 | 806 | OP_ParAppendResult res = manager->appendCHOP(sp); 807 | assert(res == OP_ParAppendResult::Success); 808 | } 809 | 810 | //Colplaneschop 811 | /*{ 812 | OP_StringParameter sp; 813 | 814 | sp.name = "Colplaneschop"; 815 | sp.label = "Collision Planes CHOP"; 816 | sp.page = "Collisions"; 817 | 818 | OP_ParAppendResult res = manager->appendCHOP(sp); 819 | assert(res == OP_ParAppendResult::Success); 820 | }*/ 821 | 822 | } 823 | 824 | void BulletCHOP::pulsePressed(const char* name) 825 | { 826 | /*if (!strcmp(name, "Reset")) 827 | { 828 | myOffset = 0.0; 829 | }*/ 830 | } 831 | -------------------------------------------------------------------------------- /CPlusPlus_Common.h: -------------------------------------------------------------------------------- 1 | /* Shared Use License: This file is owned by Derivative Inc. (Derivative) and 2 | * can only be used, and/or modified for use, in conjunction with 3 | * Derivative's TouchDesigner software, and only if you are a licensee who has 4 | * accepted Derivative's TouchDesigner license or assignment agreement (which 5 | * also govern the use of this file). You may share a modified version of this 6 | * file with another authorized licensee of Derivative's TouchDesigner software. 7 | * Otherwise, no redistribution or sharing of this file, with or without 8 | * modification, is permitted. 9 | */ 10 | 11 | /* 12 | * Produced by: 13 | * 14 | * Derivative Inc 15 | * 401 Richmond Street West, Unit 386 16 | * Toronto, Ontario 17 | * Canada M5V 3A8 18 | * 416-591-3555 19 | * 20 | * NAME: CPlusPlus_Common.h 21 | * 22 | */ 23 | 24 | /******* 25 | Derivative Developers:: Make sure the virtual function order 26 | stays the same, otherwise changes won't be backwards compatible 27 | ********/ 28 | 29 | 30 | #ifndef __CPlusPlus_Common 31 | #define __CPlusPlus_Common 32 | 33 | #define NOMINMAX 34 | 35 | #ifdef WIN32 36 | #include 37 | #include 38 | #include "GL_Extensions.h" 39 | #define DLLEXPORT __declspec (dllexport) 40 | #else 41 | #include 42 | #define DLLEXPORT 43 | #endif 44 | 45 | #include 46 | 47 | struct cudaArray; 48 | 49 | enum class OP_CPUMemPixelType : int32_t 50 | { 51 | // 8-bit per color, BGRA pixels. This is preferred for 4 channel 8-bit data 52 | BGRA8Fixed = 0, 53 | // 8-bit per color, RGBA pixels. Only use this one if absolutely nesseary. 54 | RGBA8Fixed, 55 | // 32-bit float per color, RGBA pixels 56 | RGBA32Float, 57 | 58 | // Single and double channel options 59 | // Fixed 60 | R8Fixed, 61 | RG8Fixed, 62 | // Float 63 | R32Float, 64 | RG32Float, 65 | }; 66 | 67 | 68 | 69 | class OP_NodeInfo 70 | { 71 | public: 72 | // The full path to the operator 73 | 74 | const char* opPath; 75 | 76 | // A unique ID representing the operator, no two operators will ever 77 | // have the same ID in a single TouchDesigner instance. 78 | 79 | uint32_t opID; 80 | 81 | // This is the handle to the main TouchDesigner window. 82 | // It's possible this will be 0 the first few times the operator cooks, 83 | // incase it cooks while TouchDesigner is still loading up 84 | 85 | #ifdef WIN32 86 | HWND mainWindowHandle; 87 | #endif 88 | 89 | private: 90 | int32_t reserved[19]; 91 | }; 92 | 93 | 94 | class OP_DATInput 95 | { 96 | public: 97 | const char* opPath; 98 | uint32_t opId; 99 | 100 | int32_t numRows; 101 | int32_t numCols; 102 | bool isTable; 103 | 104 | // data, referenced by (row,col), which will be a const char* for the 105 | // contents of the cell 106 | // E.g getCell(1,2) will be the contents of the cell located at (1,2) 107 | 108 | const char* 109 | getCell(int32_t row, int32_t col) const 110 | { 111 | return cellData[row * numCols + col]; 112 | } 113 | 114 | protected: 115 | const char** cellData; 116 | 117 | private: 118 | int32_t reserved[20]; 119 | }; 120 | 121 | class OP_TOPInput 122 | { 123 | public: 124 | const char* opPath; 125 | uint32_t opId; 126 | 127 | int32_t width; 128 | int32_t height; 129 | 130 | 131 | // The OpenGL Texture index for this TOP. 132 | // This is only valid when accessed from C++ TOPs. 133 | // Other C++ OPs will have this value set to 0 (invalid). 134 | GLuint textureIndex; 135 | 136 | // The OpenGL Texture target for this TOP. 137 | // E.g GL_TEXTURE_2D, GL_TEXTURE_CUBE, 138 | // GL_TEXTURE_2D_ARRAY 139 | GLenum textureType; 140 | 141 | // Depth for 3D and 2D_ARRAY textures, undefined 142 | // for other texture types 143 | uint32_t depth; 144 | 145 | // contains the internalFormat for the texture 146 | // such as GL_RGBA8, GL_RGBA32F, GL_R16 147 | GLint pixelFormat; 148 | 149 | // reserved 150 | int32_t reserved1; 151 | 152 | // When the TOP_ExecuteMode is CUDA, this will be filled in 153 | cudaArray* cudaInput; 154 | 155 | private: 156 | int32_t reserved[16]; 157 | }; 158 | 159 | 160 | class OP_CHOPInput 161 | { 162 | public: 163 | 164 | const char* opPath; 165 | uint32_t opId; 166 | 167 | int32_t numChannels; 168 | int32_t numSamples; 169 | double sampleRate; 170 | double startIndex; 171 | 172 | 173 | 174 | // Retrieve a float array for a specific channel. 175 | // 'i' ranges from 0 to numChannels-1 176 | // The returned arrray contains 'numSamples' samples. 177 | // e.g: getChannelData(1)[10] will refer to the 11th sample in the 2nd channel 178 | 179 | const float* 180 | getChannelData(int32_t i) const 181 | { 182 | return channelData[i]; 183 | } 184 | 185 | 186 | // Retrieve the name of a specific channel. 187 | // 'i' ranges from 0 to numChannels-1 188 | // For example getChannelName(1) is the name of the 2nd channel 189 | 190 | const char* 191 | getChannelName(int32_t i) const 192 | { 193 | return nameData[i]; 194 | } 195 | 196 | protected: 197 | 198 | const float** channelData; 199 | const char** nameData; 200 | 201 | 202 | private: 203 | 204 | int32_t reserved[20]; 205 | }; 206 | 207 | 208 | class OP_ObjectInput 209 | { 210 | public: 211 | 212 | const char* opPath; 213 | uint32_t opId; 214 | 215 | // Use these methods to calculate object transforms 216 | double worldTransform[4][4]; 217 | double localTransform[4][4]; 218 | 219 | 220 | private: 221 | 222 | int32_t reserved[20]; 223 | }; 224 | 225 | 226 | // The type of data the attribute holds 227 | enum class AttribType : int32_t 228 | { 229 | // One or more floats 230 | Float = 0, 231 | 232 | // One or more integers 233 | Int, 234 | }; 235 | 236 | // Right now we only support point attributes. 237 | enum class AttribSet : int32_t 238 | { 239 | Invalid, 240 | Point = 0, 241 | }; 242 | 243 | // The type of the primitives, currently only Polygon type 244 | // is supported 245 | enum class PrimitiveType : int32_t 246 | { 247 | Invalid, 248 | Polygon = 0, 249 | }; 250 | 251 | 252 | class Position 253 | { 254 | public: 255 | Position() 256 | { 257 | x = 0.0f; 258 | y = 0.0f; 259 | z = 0.0f; 260 | } 261 | Position(float xx, float yy, float zz) 262 | { 263 | x = xx; 264 | y = yy; 265 | z = zz; 266 | } 267 | 268 | float x; 269 | float y; 270 | float z; 271 | }; 272 | 273 | class Vector 274 | { 275 | public: 276 | Vector() 277 | { 278 | x = 0.0f; 279 | y = 0.0f; 280 | z = 0.0f; 281 | } 282 | Vector(float xx, float yy, float zz) 283 | { 284 | x = xx; 285 | y = yy; 286 | z = zz; 287 | } 288 | 289 | float x; 290 | float y; 291 | float z; 292 | }; 293 | 294 | class Color 295 | { 296 | public: 297 | Color () 298 | { 299 | r = 1.0f; 300 | g = 1.0f; 301 | b = 1.0f; 302 | a = 1.0f; 303 | } 304 | Color (float rr, float gg, float bb, float aa) 305 | { 306 | r = rr; 307 | g = gg; 308 | b = bb; 309 | a = aa; 310 | } 311 | 312 | float r; 313 | float g; 314 | float b; 315 | float a; 316 | }; 317 | 318 | class TexCoord 319 | { 320 | public: 321 | TexCoord() 322 | { 323 | u = 0.0f; 324 | v = 0.0f; 325 | w = 0.0f; 326 | } 327 | TexCoord(float uu, float vv, float ww) 328 | { 329 | u = uu; 330 | v = vv; 331 | w = ww; 332 | } 333 | 334 | float u; 335 | float v; 336 | float w; 337 | }; 338 | 339 | 340 | class NormalInfo 341 | { 342 | public: 343 | 344 | NormalInfo() 345 | { 346 | numNormals = 0; 347 | attribSet = AttribSet::Point; 348 | normals = nullptr; 349 | } 350 | 351 | int32_t numNormals; 352 | AttribSet attribSet; 353 | const Vector* normals; 354 | }; 355 | 356 | class ColorInfo 357 | { 358 | public: 359 | 360 | ColorInfo() 361 | { 362 | numColors = 0; 363 | attribSet = AttribSet::Point; 364 | colors = nullptr; 365 | } 366 | 367 | int32_t numColors; 368 | AttribSet attribSet; 369 | const Color* colors; 370 | }; 371 | 372 | class TextureInfo 373 | { 374 | public: 375 | 376 | TextureInfo() 377 | { 378 | numTexture = 0; 379 | attribSet = AttribSet::Point; 380 | textures = nullptr; 381 | numTextureLayers = 0; 382 | } 383 | 384 | int32_t numTexture; 385 | AttribSet attribSet; 386 | const TexCoord* textures; 387 | int32_t numTextureLayers; 388 | }; 389 | 390 | 391 | // CustomAttribInfo, all the required data for each custom attribute 392 | // this info can be queried by calling getCustomAttribute() which accepts 393 | // two types of argument: 394 | // 1) a valid index of a custom attribute 395 | // 2) a valid name of a custom attribute 396 | class CustomAttribInfo 397 | { 398 | public: 399 | 400 | CustomAttribInfo() 401 | { 402 | name = nullptr; 403 | numComponents = 0; 404 | attribType = AttribType::Float; 405 | floatData = nullptr; 406 | intData = nullptr; 407 | } 408 | 409 | const char* name; 410 | int32_t numComponents; 411 | AttribType attribType; 412 | 413 | const float* floatData; 414 | const int32_t* intData; 415 | 416 | }; 417 | 418 | // PrimitiveInfo, all the required data for each primitive 419 | // this info can be queried by calling getPrimitive() which accepts 420 | // a valid index of a primitive as an input argument 421 | class PrimitiveInfo 422 | { 423 | public: 424 | 425 | PrimitiveInfo() 426 | { 427 | pointIndices = nullptr; 428 | numVertices = 0; 429 | type = PrimitiveType::Invalid; 430 | pointIndicesOffset = 0; 431 | } 432 | 433 | // number of vertices of this prim 434 | int32_t numVertices; 435 | 436 | // all the indices of the vertices of the primitive. This array has 437 | // numVertices entries in it 438 | const int32_t* pointIndices; 439 | 440 | // The type of this primitive 441 | PrimitiveType type; 442 | 443 | // the offset of the this primitive's point indices in the index array 444 | // returned from getAllPrimPointIndices() 445 | int32_t pointIndicesOffset; 446 | 447 | }; 448 | 449 | 450 | 451 | 452 | 453 | 454 | class OP_SOPInput 455 | { 456 | public: 457 | 458 | virtual ~OP_SOPInput() 459 | { 460 | } 461 | 462 | 463 | 464 | const char* opPath; 465 | uint32_t opId; 466 | 467 | 468 | // Returns the total number of points 469 | virtual int32_t getNumPoints() const = 0; 470 | 471 | // The total number of vertices, across all primitives. 472 | virtual int32_t getNumVertices() const = 0; 473 | 474 | // The total number of primitives 475 | virtual int32_t getNumPrimitives() const = 0; 476 | 477 | // The total number of custom attributes 478 | virtual int32_t getNumCustomAttributes() const = 0; 479 | 480 | // Returns an array of point positions. This array is getNumPoints() long. 481 | virtual const Position* getPointPositions() const = 0; 482 | 483 | // Returns an array of normals. 484 | // 485 | // Returns nullptr if no normals are present 486 | virtual const NormalInfo* getNormals() const = 0; 487 | 488 | // Returns an array of colors. 489 | // Returns nullptr if no colors are present 490 | virtual const ColorInfo* getColors() const = 0; 491 | 492 | // Returns an array of texture coordinates. 493 | // If multiple texture coordinate layers are present, they will be placed 494 | // interleaved back-to-back. 495 | // E.g layer0 followed by layer1 followed by layer0 etc. 496 | // 497 | // Returns nullptr if no texture layers are present 498 | virtual const TextureInfo* getTextures() const = 0; 499 | 500 | // Returns the custom attribute info with an input index 501 | virtual const CustomAttribInfo* getCustomAttribute(int32_t customAttribIndex) const = 0; 502 | 503 | // Returns the custom attribute info with its name 504 | virtual const CustomAttribInfo* getCustomAttribute(const char* customAttribName) const = 0; 505 | 506 | // Returns true if the SOP has a normal attribute of the given source 507 | // attribute 'N' 508 | virtual bool hasNormals() const = 0; 509 | 510 | // Returns true if the SOP has a color the given source 511 | // attribute 'Cd' 512 | virtual bool hasColors() const = 0; 513 | 514 | // Returns the PrimitiveInfo with primIndex 515 | const PrimitiveInfo 516 | getPrimitive(int32_t primIndex) const 517 | { 518 | return myPrimsInfo[primIndex]; 519 | } 520 | 521 | //// Returns the full list of all the point indices for all primitives. 522 | //// The primitives are stored back to back in this array. 523 | //// This is a faster but harder way to work with primitives than 524 | //// getPrimPointIndices() 525 | const int32_t* 526 | getAllPrimPointIndices() 527 | { 528 | return myPrimPointIndices; 529 | } 530 | 531 | 532 | protected: 533 | 534 | // Don't try to access these directly, use the public functions 535 | 536 | PrimitiveInfo* myPrimsInfo; 537 | const int32_t* myPrimPointIndices; 538 | 539 | 540 | private: 541 | 542 | int32_t reserved[100]; 543 | }; 544 | 545 | 546 | enum class OP_TOPInputDownloadType : int32_t 547 | { 548 | // The texture data will be downloaded and and available on the next frame. 549 | // Except for the first time this is used, getTOPDataInCPUMemory() 550 | // will return the texture data on the CPU from the previous frame. 551 | // The first getTOPDataInCPUMemory() is called it will be nullptr. 552 | // ** This mode should be used is most cases for performance reasons ** 553 | Delayed = 0, 554 | 555 | // The texture data will be downloaded immediately and be available 556 | // this frame. This can cause a large stall though and should be avoided 557 | // in most cases 558 | Instant, 559 | }; 560 | 561 | class OP_TOPInputDownloadOptions 562 | { 563 | public: 564 | OP_TOPInputDownloadOptions() 565 | { 566 | downloadType = OP_TOPInputDownloadType::Delayed; 567 | verticalFlip = false; 568 | cpuMemPixelType = OP_CPUMemPixelType::BGRA8Fixed; 569 | } 570 | 571 | OP_TOPInputDownloadType downloadType; 572 | 573 | // Set this to true if you want the image vertically flipped in the 574 | // downloaded data 575 | bool verticalFlip; 576 | 577 | // Set this to how you want the pixel data to be give to you in CPU 578 | // memory. BGRA8Fixed should be used for 4 channel 8-bit data if possible 579 | OP_CPUMemPixelType cpuMemPixelType; 580 | 581 | }; 582 | 583 | 584 | class OP_Inputs 585 | { 586 | public: 587 | // NOTE: When writting a TOP, none of these functions should 588 | // be called inside a beginGLCommands()/endGLCommands() section 589 | // as they may require GL themselves to complete execution. 590 | 591 | // these are wired into the node 592 | virtual int32_t getNumInputs() = 0; 593 | 594 | // may return nullptr when invalid input 595 | // only valid for C++ TOP operators 596 | virtual const OP_TOPInput* getInputTOP(int32_t index) = 0; 597 | // only valid for C++ CHOP operators 598 | virtual const OP_CHOPInput* getInputCHOP(int32_t index) = 0; 599 | // getInputSOP() declared later on in the class 600 | 601 | // these are defined by parameters. 602 | // may return nullptr when invalid input 603 | // this value is valid until the parameters are rebuilt or it is called with the same parameter name. 604 | virtual const OP_DATInput* getParDAT(const char *name) = 0; 605 | virtual const OP_TOPInput* getParTOP(const char *name) = 0; 606 | virtual const OP_CHOPInput* getParCHOP(const char *name) = 0; 607 | virtual const OP_ObjectInput* getParObject(const char *name) = 0; 608 | // getParSOP() declared later on in the class 609 | 610 | // these work on any type of parameter and can be interchanged 611 | // for menu types, int returns the menu selection index, string returns the item 612 | 613 | // returns the requested value, index may be 0 to 4. 614 | virtual double getParDouble(const char* name, int32_t index = 0) = 0; 615 | 616 | // for multiple values: returns True on success/false otherwise 617 | virtual bool getParDouble2(const char* name, double &v0, double &v1) = 0; 618 | virtual bool getParDouble3(const char* name, double &v0, double &v1, double &v2) = 0; 619 | virtual bool getParDouble4(const char* name, double &v0, double &v1, double &v2, double &v3) = 0; 620 | 621 | 622 | // returns the requested value 623 | virtual int32_t getParInt(const char* name, int32_t index = 0) = 0; 624 | 625 | // for multiple values: returns True on success/false otherwise 626 | virtual bool getParInt2(const char* name, int32_t &v0, int32_t &v1) = 0; 627 | virtual bool getParInt3(const char* name, int32_t &v0, int32_t &v1, int32_t &v2) = 0; 628 | virtual bool getParInt4(const char* name, int32_t &v0, int32_t &v1, int32_t &v2, int32_t &v3) = 0; 629 | 630 | // returns the requested value 631 | // this value is valid until the parameters are rebuilt or it is called with the same parameter name. 632 | // return value usable for life of parameter 633 | virtual const char* getParString(const char* name) = 0; 634 | 635 | 636 | // this is similar to getParString, but will return an absolute path if it exists, with 637 | // slash direction consistent with O/S requirements. 638 | // to get the original parameter value, use getParString 639 | // return value usable for life of parameter 640 | virtual const char* getParFilePath(const char* name) = 0; 641 | 642 | // returns true on success 643 | // from_name and to_name must be Object parameters 644 | virtual bool getRelativeTransform(const char* from_name, const char* to_name, double matrix[4][4]) = 0; 645 | 646 | 647 | // disable or enable updating of the parameter 648 | virtual void enablePar(const char* name, bool onoff) = 0; 649 | 650 | 651 | // these are defined by paths. 652 | // may return nullptr when invalid input 653 | // this value is valid until the parameters are rebuilt or it is called with the same parameter name. 654 | virtual const OP_DATInput* getDAT(const char *path) = 0; 655 | virtual const OP_TOPInput* getTOP(const char *path) = 0; 656 | virtual const OP_CHOPInput* getCHOP(const char *path) = 0; 657 | virtual const OP_SOPInput* getSOP(const char *path) = 0; 658 | virtual const OP_ObjectInput* getObject(const char *path) = 0; 659 | 660 | 661 | // This function can be used to retrieve the TOPs texture data in CPU 662 | // memory. You must pass the OP_TOPInput object you get from 663 | // getParTOP/getInputTOP into this, not a copy you've made 664 | // 665 | // Fill in a OP_TOPIputDownloadOptions class with the desired options set 666 | // 667 | // Returns the data, which will be valid until the end of execute() 668 | // Returned value may be nullptr in some cases, such as the first call 669 | // to this with options->downloadType == OP_TOP_DOWNLOAD_DELAYED. 670 | virtual void* getTOPDataInCPUMemory(const OP_TOPInput *top, 671 | const OP_TOPInputDownloadOptions *options) = 0; 672 | 673 | 674 | virtual const OP_SOPInput* getParSOP(const char *name) = 0; 675 | // only valid for C++ SOP operators 676 | virtual const OP_SOPInput* getInputSOP(int32_t index) = 0; 677 | 678 | }; 679 | 680 | class OP_InfoCHOPChan 681 | { 682 | public: 683 | const char* name; 684 | float value; 685 | private: 686 | int32_t reserved[10]; 687 | }; 688 | 689 | class OP_InfoDATSize 690 | { 691 | public: 692 | 693 | // Set this to the size you want the table to be 694 | 695 | int32_t rows; 696 | int32_t cols; 697 | 698 | // Set this to true if you want to return DAT entries on a column 699 | // by column basis. 700 | // Otherwise set to false, and you'll be expected to set them on 701 | // a row by row basis. 702 | // DEFAULT : false 703 | 704 | bool byColumn; 705 | 706 | 707 | private: 708 | int32_t reserved[10]; 709 | }; 710 | 711 | class OP_InfoDATEntries 712 | { 713 | public: 714 | 715 | // This is an array of char* pointers which you are expected to assign 716 | // The start off as NULL, you need to allocate or assign constant/statis 717 | // strings to them 718 | // e.g values[1] = "myColumnName"; 719 | 720 | char** values; 721 | 722 | private: 723 | int32_t reserved[10]; 724 | }; 725 | 726 | 727 | 728 | class OP_NumericParameter 729 | { 730 | public: 731 | 732 | OP_NumericParameter(const char* iname = nullptr) 733 | { 734 | name = iname; 735 | label = page = nullptr; 736 | 737 | for (int i = 0; i<4; i++) 738 | { 739 | defaultValues[i] = 0.0; 740 | 741 | minSliders[i] = 0.0; 742 | maxSliders[i] = 1.0; 743 | 744 | minValues[i] = 0.0; 745 | maxValues[i] = 1.0; 746 | 747 | clampMins[i] = false; 748 | clampMaxes[i] = false; 749 | } 750 | } 751 | 752 | // Any char* values passed are copied immediately by the append parameter functions, 753 | // and do not need to be retained by the calling function. 754 | // Must begin with capital letter, and contain no spaces 755 | const char* name; 756 | const char* label; 757 | const char* page; 758 | 759 | double defaultValues[4]; 760 | double minValues[4]; 761 | double maxValues[4]; 762 | 763 | bool clampMins[4]; 764 | bool clampMaxes[4]; 765 | 766 | double minSliders[4]; 767 | double maxSliders[4]; 768 | 769 | private: 770 | 771 | int32_t reserved[20]; 772 | 773 | }; 774 | 775 | class OP_StringParameter 776 | { 777 | public: 778 | 779 | OP_StringParameter(const char* iname = nullptr) 780 | { 781 | name = iname; 782 | label = page = nullptr; 783 | defaultValue = nullptr; 784 | } 785 | 786 | // Any char* values passed are copied immediately by the append parameter functions, 787 | // and do not need to be retained by the calling function. 788 | 789 | // Must begin with capital letter, and contain no spaces 790 | const char* name; 791 | const char* label; 792 | const char* page; 793 | 794 | const char* defaultValue; 795 | 796 | private: 797 | 798 | int32_t reserved[20]; 799 | }; 800 | 801 | 802 | enum class OP_ParAppendResult : int32_t 803 | { 804 | Success = 0, 805 | InvalidName, // invalid or duplicate name 806 | InvalidSize, // size out of range 807 | }; 808 | 809 | 810 | class OP_ParameterManager 811 | { 812 | 813 | public: 814 | 815 | // Returns PARAMETER_APPEND_SUCCESS on succesful 816 | 817 | virtual OP_ParAppendResult appendFloat(const OP_NumericParameter &np, int32_t size = 1) = 0; 818 | virtual OP_ParAppendResult appendInt(const OP_NumericParameter &np, int32_t size = 1) = 0; 819 | 820 | virtual OP_ParAppendResult appendXY(const OP_NumericParameter &np) = 0; 821 | virtual OP_ParAppendResult appendXYZ(const OP_NumericParameter &np) = 0; 822 | 823 | virtual OP_ParAppendResult appendUV(const OP_NumericParameter &np) = 0; 824 | virtual OP_ParAppendResult appendUVW(const OP_NumericParameter &np) = 0; 825 | 826 | virtual OP_ParAppendResult appendRGB(const OP_NumericParameter &np) = 0; 827 | virtual OP_ParAppendResult appendRGBA(const OP_NumericParameter &np) = 0; 828 | 829 | virtual OP_ParAppendResult appendToggle(const OP_NumericParameter &np) = 0; 830 | virtual OP_ParAppendResult appendPulse(const OP_NumericParameter &np) = 0; 831 | 832 | virtual OP_ParAppendResult appendString(const OP_StringParameter &sp) = 0; 833 | virtual OP_ParAppendResult appendFile(const OP_StringParameter &sp) = 0; 834 | virtual OP_ParAppendResult appendFolder(const OP_StringParameter &sp) = 0; 835 | 836 | virtual OP_ParAppendResult appendDAT(const OP_StringParameter &sp) = 0; 837 | virtual OP_ParAppendResult appendCHOP(const OP_StringParameter &sp) = 0; 838 | virtual OP_ParAppendResult appendTOP(const OP_StringParameter &sp) = 0; 839 | virtual OP_ParAppendResult appendObject(const OP_StringParameter &sp) = 0; 840 | // appendSOP() located further down in the class 841 | 842 | 843 | // Any char* values passed are copied immediately by the append parameter functions, 844 | // and do not need to be retained by the calling function. 845 | virtual OP_ParAppendResult appendMenu(const OP_StringParameter &sp, 846 | int32_t nitems, const char **names, 847 | const char **labels) = 0; 848 | 849 | // Any char* values passed are copied immediately by the append parameter functions, 850 | // and do not need to be retained by the calling function. 851 | virtual OP_ParAppendResult appendStringMenu(const OP_StringParameter &sp, 852 | int32_t nitems, const char **names, 853 | const char **labels) = 0; 854 | 855 | virtual OP_ParAppendResult appendSOP(const OP_StringParameter &sp) = 0; 856 | 857 | private: 858 | 859 | 860 | }; 861 | 862 | #endif 863 | --------------------------------------------------------------------------------