├── .gitignore ├── README.md ├── blurPython.cpp ├── blurPython.def ├── blurPython.h ├── blurPython.rc ├── blurPython_msvc2005.sln ├── blurPython_msvc2005.vcproj ├── blurPython_msvc2005_sp1.sln ├── blurPython_msvc2005_sp1.vcproj ├── blurPython_msvc2008.sln ├── blurPython_msvc2008.vcproj ├── blurPython_msvc2010.sln ├── blurPython_msvc2010.vcproj ├── blurPython_msvc2010.vcxproj ├── blurPython_msvc2010.vcxproj.filters ├── blurPython_msvc2012.sln ├── blurPython_msvc2012.vcxproj ├── blurPython_msvc2012.vcxproj.filters ├── buildVersion.py ├── docs ├── make.bat └── source │ ├── _static │ ├── blur.ico │ ├── blur.png │ ├── blur_large.png │ └── blursphinx.css │ ├── _templates │ ├── __static │ │ ├── blur.ico │ │ ├── blur.png │ │ └── blur_large.png │ ├── indexcontent.html │ └── layout.html │ ├── bugs.rst │ ├── conf.py │ ├── contents.rst │ ├── copyright.rst │ ├── rst_maker.py │ └── tutorial │ └── index.rst ├── imports.h ├── license.txt ├── macros.h ├── protector.cpp ├── protector.h ├── python_struct.cpp ├── resource.h ├── studiomax_module.cpp ├── version_h_template.txt ├── wrapper.cpp └── wrapper.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Auto generated files 2 | version.h 3 | # Don't commit the generated pluging file. 4 | *.dlx 5 | 6 | ################# 7 | ## Eclipse 8 | ################# 9 | 10 | *.pydevproject 11 | .project 12 | .metadata 13 | bin/ 14 | tmp/ 15 | *.tmp 16 | *.bak 17 | *.swp 18 | *~.nib 19 | local.properties 20 | .classpath 21 | .settings/ 22 | .loadpath 23 | 24 | # External tool builders 25 | .externalToolBuilders/ 26 | 27 | # Locally stored "Eclipse launch configurations" 28 | *.launch 29 | 30 | # CDT-specific 31 | .cproject 32 | 33 | # PDT-specific 34 | .buildpath 35 | 36 | 37 | ################# 38 | ## Visual Studio 39 | ################# 40 | 41 | ## Ignore Visual Studio temporary files, build results, and 42 | ## files generated by popular Visual Studio add-ons. 43 | 44 | # User-specific files 45 | *.suo 46 | *.user 47 | *.sln.docstates 48 | *.sdf 49 | 50 | # Build results 51 | 52 | [Dd]ebug/ 53 | [Rr]elease/ 54 | x64/ 55 | build/ 56 | [Bb]in/ 57 | [Oo]bj/ 58 | 59 | # MSTest test Results 60 | [Tt]est[Rr]esult*/ 61 | [Bb]uild[Ll]og.* 62 | 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 | *.tmp_proj 79 | *.log 80 | *.vspscc 81 | *.vssscc 82 | .builds 83 | *.pidb 84 | *.log 85 | *.scc 86 | 87 | # Visual C++ cache files 88 | ipch/ 89 | *.aps 90 | *.ncb 91 | *.opensdf 92 | *.sdf 93 | *.cachefile 94 | 95 | # Visual Studio profiler 96 | *.psess 97 | *.vsp 98 | *.vspx 99 | 100 | # Guidance Automation Toolkit 101 | *.gpState 102 | 103 | # ReSharper is a .NET coding add-in 104 | _ReSharper*/ 105 | *.[Rr]e[Ss]harper 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | *.ncrunch* 115 | .*crunch*.local.xml 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.Publish.xml 135 | *.pubxml 136 | *.publishproj 137 | 138 | # NuGet Packages Directory 139 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 140 | #packages/ 141 | 142 | # Windows Azure Build Output 143 | csx 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.[Pp]ublish.xml 158 | *.pfx 159 | *.publishsettings 160 | 161 | # RIA/Silverlight projects 162 | Generated_Code/ 163 | 164 | # Backup & report files from converting an old project file to a newer 165 | # Visual Studio version. Backup files are not needed, because we have git ;-) 166 | _UpgradeReport_Files/ 167 | Backup*/ 168 | UpgradeLog*.XML 169 | UpgradeLog*.htm 170 | 171 | # SQL Server files 172 | App_Data/*.mdf 173 | App_Data/*.ldf 174 | 175 | ############# 176 | ## Windows detritus 177 | ############# 178 | 179 | # Windows image file caches 180 | Thumbs.db 181 | ehthumbs.db 182 | 183 | # Folder config file 184 | Desktop.ini 185 | 186 | # Recycle Bin used on file shares 187 | $RECYCLE.BIN/ 188 | 189 | # Mac crap 190 | .DS_Store 191 | 192 | 193 | ############# 194 | ## Python 195 | ############# 196 | 197 | *.py[cod] 198 | 199 | # Packages 200 | *.egg 201 | *.egg-info 202 | dist/ 203 | build/ 204 | eggs/ 205 | parts/ 206 | var/ 207 | sdist/ 208 | develop-eggs/ 209 | .installed.cfg 210 | 211 | # Installer logs 212 | pip-log.txt 213 | 214 | # Unit test / coverage reports 215 | .coverage 216 | .tox 217 | 218 | #Translations 219 | *.mo 220 | 221 | #Mr Developer 222 | .mr.developer.cfg 223 | blurPython_msvc2012.sdf 224 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Py3dsMax allows two way access between the maxscript and python interpreters. In maxscript you can import python modules and classes create objects set values etc. In python you can access maxscript commands get and set values. 2 | 3 | Some non-pythonic functionality does not translate to python like the by-reference character "&". To work around these limitations you can generally define a helper maxscript struct like the pyhelper class. 4 | 5 | # Compile Settings 6 | 7 | There are several environment variables you will need to set to be able to compile. Most of them contain the year of the max version you are trying to comile for. For example to compile for Max 2015 you need to create a environment variable "MAX2015SDK" pointing to the maxsdk folder of the sdk(C:\Program Files\Autodesk\3ds Max 2015 SDK\maxsdk). 8 | 9 | Required Environment variables: 10 | 11 | 1. MAX[year]SDK: The Max SDK's location. should point to the maxsdk folder. year is the year number of the max build you are trying to build. 12 | 2. PYTHON[ver][_64]: The folder containing python.exe. ver is the python version without a decimal. _64 should be specified for 64bit builds, and should be omitted for 32bit builds. 13 | 3. MAX[Year]OUT: If defined as a post-build process the .dlx file will be copied to this folder. This variable is optional, and is only supported in Max 2015 and newer. 14 | 15 | Here is a breakdown of the Visual Studio requirements required to build this package. If a binary compatible version is listed you can use the same plugin compiled for that version. 16 | 17 | | | 2012 | 2013 | 2014 | 2015 | 2016 | 18 | |------------------------|------------------------------------------------|---------------------------------------------------|----------------------|-----------------------------|-----------------------------| 19 | | Visual Studio | 2008 Service Pack 1 | 2010 Service Pack 1 | 2010 Service Pack 1 | Visual Studio 2012 Update 4 | Visual Studio 2012 Update 4 | 20 | | Binary Compatible | | | | | 2015 | 21 | | 32bit Python Version | PYTHON24 | PYTHON27 | Not Supported | Not Supported | Not Supported | 22 | | 64bit Python Version | PYTHON26_64 PYTHON27_64 | PYTHON27_64 | PYTHON27_64 | PYTHON27_64 | PYTHON27_64 | 23 | | Configuration/Platform | Max2012_Python24/Win32 Max2012x64_Python26/x64 | Max2013x32_Python27/Win32 Max2013x64_Python27/x64 | Max2014_Python27/x64 | Max2015x64_Python27/x64 | Max2015x64_Python27/x64 | 24 | 25 | Compiled output goes in [project]/bin/[platform]/Max[year]_Python[ver]/ or for older versions it may go into [project]/bin/[platform]/[configuration]/ 26 | 27 | # Install 28 | 29 | * Copy the .dlx file into your plugins folder. 30 | * Create the following startup script in your scripts/startup folder. 31 | 32 | ``` 33 | -- Check if the Python DLL is installed 34 | if ( pymax != undefined ) then ( 35 | -- Starting with Max 2015 we need to initialize Autodesk's python before our python is initialized 36 | if (python != undefined) and (finditem (getPropNames python) #exec == 0) do 37 | python.init() 38 | -- pymax did not have a init method in the past. 39 | if (finditem (getPropNames pymax) #init != 0) do 40 | pymax.init() 41 | ``` 42 | -------------------------------------------------------------------------------- /blurPython.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | \file blurPython.cpp 3 | 4 | \remarks Entry point for the blurPython dlx 5 | 6 | \author Blur Studio (c) 2010 7 | \email beta@blur.com 8 | 9 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 10 | */ 11 | 12 | #include "imports.h" 13 | 14 | #pragma comment( lib, "comctl32.lib" ) 15 | 16 | //------------------------------------------------------------------------------------------------------ 17 | HMODULE hInstance = NULL; 18 | HINSTANCE g_hInst; 19 | 20 | BOOL APIENTRY DLLMain( HMODULE hModule, DWORD ul_reason, LPVOID lpReserved ) { 21 | INITCOMMONCONTROLSEX icex; 22 | icex.dwSize = sizeof( icex ); 23 | icex.dwICC = ICC_TREEVIEW_CLASSES | ICC_LISTVIEW_CLASSES; 24 | 25 | switch ( ul_reason ) { 26 | case DLL_PROCESS_ATTACH: { 27 | hInstance = hModule; 28 | g_hInst = hModule; 29 | 30 | DisableThreadLibraryCalls( hModule ); 31 | break; 32 | } 33 | case DLL_PROCESS_DETACH: { 34 | // Kill the python system 35 | #ifndef __MAXSCRIPT_2015__ 36 | // This should only be run in versions of max that don't have python native integration 37 | Py_Finalize(); 38 | #endif 39 | } 40 | } 41 | 42 | return TRUE; 43 | } 44 | 45 | // the init_module function is found in the studiomax_module file 46 | #ifdef __MAXSCRIPT_2015__ 47 | // calling init_module when LibInit is called will cause max to crash. 48 | __declspec( dllexport ) void LibInit() {} 49 | #else 50 | PyMODINIT_FUNC init_module(); 51 | 52 | __declspec( dllexport ) void LibInit() { init_module(); } 53 | #endif 54 | 55 | __declspec( dllexport ) const TCHAR* LibDescription() { return _T( "Py3dsMax Python Extension" ); } 56 | __declspec( dllexport ) ULONG LibVersion() { return VERSION_3DSMAX; } 57 | 58 | // Maxscript 2012 requires these additional exports 59 | #if __MAXSCRIPT_2012__ || __MAXSCRIPT_2013__ || __MAXSCRIPT_2015__ 60 | 61 | // we aren't defining any classes in this plugin, so this is pretty easy 62 | // other plugins should refer to samples/scriptplugin for an example of the new 63 | // registration system - that is the only plugin that does not error out of the samples 64 | // in max 65 | __declspec( dllexport ) int LibNumberClasses() { return 0; } 66 | __declspec( dllexport ) ClassDesc* LibClassDesc( int i ) { return 0; } 67 | 68 | #endif -------------------------------------------------------------------------------- /blurPython.def: -------------------------------------------------------------------------------- 1 | LIBRARY blurPython.dlx 2 | EXPORTS 3 | LibDescription @1 PRIVATE 4 | LibInit @2 PRIVATE 5 | LibVersion @3 PRIVATE 6 | LibNumberClasses @4 PRIVATE 7 | LibClassDesc @5 PRIVATE 8 | SECTIONS 9 | .data READ WRITE 10 | -------------------------------------------------------------------------------- /blurPython.h: -------------------------------------------------------------------------------- 1 | #ifndef __BLURPYTHON_H__ 2 | #define __BLURPYTHON_H__ 3 | 4 | #include "IPathConfigMgr.h" 5 | 6 | // the initialize_blurpython function is found in the studiomax_module file 7 | PyMODINIT_FUNC initialize_blurpython(); 8 | 9 | void BlurPythonInit() { 10 | // Step 1: initialize the blur plugin 11 | init_plugin( "blurPython", 1100 ); 12 | 13 | // Step 2: initialize python 14 | Py_Initialize(); 15 | 16 | // Step 3: initialize 3dsMax 17 | initialize_blurpython(); 18 | } 19 | 20 | #endif __BLURPYTHON_H__ -------------------------------------------------------------------------------- /blurPython.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | 3 | #include "resource.h" 4 | #include "version.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "windows.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (U.S.) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | #ifdef _WIN32 21 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 22 | #pragma code_page(1252) 23 | #endif //_WIN32 24 | 25 | #ifdef APSTUDIO_INVOKED 26 | ///////////////////////////////////////////////////////////////////////////// 27 | // 28 | // TEXTINCLUDE 29 | // 30 | 31 | 1 TEXTINCLUDE 32 | BEGIN 33 | "resource.h\0" 34 | END 35 | 36 | 2 TEXTINCLUDE 37 | BEGIN 38 | "#include ""windows.h""\r\n" 39 | "\0" 40 | END 41 | 42 | 3 TEXTINCLUDE 43 | BEGIN 44 | "\r\n" 45 | "\0" 46 | END 47 | 48 | #endif // APSTUDIO_INVOKED 49 | 50 | 51 | ///////////////////////////////////////////////////////////////////////////// 52 | // 53 | // Version 54 | // 55 | 56 | VS_VERSION_INFO VERSIONINFO 57 | FILEVERSION BLURPYTHON_VERSION_MAJOR,BLURPYTHON_VERSION_MINOR,BLURPYTHON_VERSION_PATCH,BLURPYTHON_VERSION_REV 58 | FILEFLAGSMASK 0x17L 59 | #ifdef _DEBUG 60 | FILEFLAGS 0x1L 61 | #else 62 | FILEFLAGS 0x0L 63 | #endif 64 | FILEOS 0x4L 65 | FILETYPE 0x2L 66 | FILESUBTYPE 0x0L 67 | BEGIN 68 | BLOCK "StringFileInfo" 69 | BEGIN 70 | BLOCK "040904b0" 71 | BEGIN 72 | VALUE "Comments", "Blur Py3dsMax Plugin" 73 | VALUE "CompanyName", "Blur Studio" 74 | VALUE "FileDescription", "blurPython Dynamic Link Library" 75 | VALUE "FileVersion", BLURPYTHON_VERSION_STR 76 | VALUE "Build Date", BLURPYTHON_BUILDDATE 77 | VALUE "ProductName", "blurPython Dynamic Link Library" 78 | END 79 | END 80 | BLOCK "VarFileInfo" 81 | BEGIN 82 | VALUE "Translation", 0x409, 1200 83 | END 84 | END 85 | 86 | #endif // English (U.S.) resources 87 | ///////////////////////////////////////////////////////////////////////////// 88 | 89 | 90 | 91 | #ifndef APSTUDIO_INVOKED 92 | ///////////////////////////////////////////////////////////////////////////// 93 | // 94 | // Generated from the TEXTINCLUDE 3 resource. 95 | // 96 | 97 | 98 | ///////////////////////////////////////////////////////////////////////////// 99 | #endif // not APSTUDIO_INVOKED 100 | 101 | -------------------------------------------------------------------------------- /blurPython_msvc2005.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blurPython_msvc2005", "blurPython_msvc2005.vcproj", "{3061FD4F-4018-429F-82B7-E30592BACA37}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Max9-10_Python24|Win32 = Max9-10_Python24|Win32 9 | Max9-10_Python24|x64 = Max9-10_Python24|x64 10 | Max9-10x64_Python26|Win32 = Max9-10x64_Python26|Win32 11 | Max9-10x64_Python26|x64 = Max9-10x64_Python26|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10_Python24|Win32.ActiveCfg = Max9-10_Python24|Win32 15 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10_Python24|Win32.Build.0 = Max9-10_Python24|Win32 16 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10_Python24|x64.ActiveCfg = Max9-10_Python24|x64 17 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10_Python24|x64.Build.0 = Max9-10_Python24|x64 18 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10x64_Python26|Win32.ActiveCfg = Max9-10x64_Python26|Win32 19 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10x64_Python26|Win32.Build.0 = Max9-10x64_Python26|Win32 20 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10x64_Python26|x64.ActiveCfg = Max9-10x64_Python26|x64 21 | {3061FD4F-4018-429F-82B7-E30592BACA37}.Max9-10x64_Python26|x64.Build.0 = Max9-10x64_Python26|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /blurPython_msvc2005.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 21 | 31 | 34 | 37 | 40 | 43 | 46 | 61 | 64 | 67 | 70 | 85 | 88 | 91 | 94 | 97 | 100 | 103 | 106 | 109 | 110 | 116 | 119 | 122 | 125 | 128 | 131 | 139 | 142 | 145 | 148 | 155 | 158 | 161 | 164 | 167 | 170 | 173 | 176 | 179 | 180 | 188 | 191 | 194 | 197 | 200 | 204 | 213 | 216 | 219 | 222 | 231 | 234 | 237 | 240 | 243 | 246 | 249 | 252 | 255 | 256 | 262 | 265 | 268 | 271 | 274 | 277 | 284 | 287 | 290 | 293 | 303 | 306 | 309 | 312 | 315 | 318 | 321 | 324 | 327 | 328 | 329 | 330 | 331 | 332 | 335 | 338 | 339 | 342 | 343 | 346 | 347 | 350 | 351 | 352 | 355 | 358 | 359 | 362 | 363 | 366 | 367 | 370 | 371 | 372 | 375 | 376 | 379 | 380 | 381 | 382 | 383 | 384 | -------------------------------------------------------------------------------- /blurPython_msvc2005_sp1.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blurPython_msvc2005_sp1", "blurPython_msvc2005_sp1.vcproj", "{78FEBC09-C6EB-4D5F-A7A2-6D580847783E}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Max10_Python24|Win32 = Max10_Python24|Win32 11 | Max10_Python24|x64 = Max10_Python24|x64 12 | Max10_Python25|Win32 = Max10_Python25|Win32 13 | Max10_Python25|x64 = Max10_Python25|x64 14 | Max10_Python26|Win32 = Max10_Python26|Win32 15 | Max10_Python26|x64 = Max10_Python26|x64 16 | Max2009_Python24|Win32 = Max2009_Python24|Win32 17 | Max2009_Python24|x64 = Max2009_Python24|x64 18 | Max2009x64_Python26_Hybrid|Win32 = Max2009x64_Python26_Hybrid|Win32 19 | Max2009x64_Python26_Hybrid|x64 = Max2009x64_Python26_Hybrid|x64 20 | Max2009x64_Python26|Win32 = Max2009x64_Python26|Win32 21 | Max2009x64_Python26|x64 = Max2009x64_Python26|x64 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Debug|Win32.Build.0 = Debug|Win32 26 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Debug|x64.ActiveCfg = Debug|x64 27 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Debug|x64.Build.0 = Debug|x64 28 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python24|Win32.ActiveCfg = Max10_Python24|Win32 29 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python24|Win32.Build.0 = Max10_Python24|Win32 30 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python24|x64.ActiveCfg = Max10_Python24|x64 31 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python24|x64.Build.0 = Max10_Python24|x64 32 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python25|Win32.ActiveCfg = Max10_Python25|Win32 33 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python25|Win32.Build.0 = Max10_Python25|Win32 34 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python25|x64.ActiveCfg = Max10_Python25|x64 35 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python25|x64.Build.0 = Max10_Python25|x64 36 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python26|Win32.ActiveCfg = Max10_Python26|Win32 37 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python26|Win32.Build.0 = Max10_Python26|Win32 38 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python26|x64.ActiveCfg = Max10_Python26|x64 39 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max10_Python26|x64.Build.0 = Max10_Python26|x64 40 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009_Python24|Win32.ActiveCfg = Max2009_Python24|Win32 41 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009_Python24|x64.ActiveCfg = Max2009_Python24|x64 42 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009_Python24|x64.Build.0 = Max2009_Python24|x64 43 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009x64_Python26_Hybrid|Win32.ActiveCfg = Max2009x64_Python26_Hybrid|x64 44 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009x64_Python26_Hybrid|Win32.Build.0 = Max2009x64_Python26_Hybrid|x64 45 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009x64_Python26_Hybrid|x64.ActiveCfg = Max2009x64_Python26_Hybrid|x64 46 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009x64_Python26_Hybrid|x64.Build.0 = Max2009x64_Python26_Hybrid|x64 47 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009x64_Python26|Win32.ActiveCfg = Max2009x64_Python26|Win32 48 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009x64_Python26|Win32.Build.0 = Max2009x64_Python26|Win32 49 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2009x64_Python26|x64.ActiveCfg = Max2009x64_Python26|x64 50 | EndGlobalSection 51 | GlobalSection(SolutionProperties) = preSolution 52 | HideSolutionNode = FALSE 53 | EndGlobalSection 54 | EndGlobal 55 | -------------------------------------------------------------------------------- /blurPython_msvc2005_sp1.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 21 | 28 | 32 | 35 | 38 | 41 | 44 | 57 | 60 | 63 | 66 | 79 | 82 | 85 | 88 | 91 | 94 | 97 | 100 | 104 | 105 | 112 | 116 | 119 | 122 | 125 | 129 | 142 | 145 | 148 | 151 | 164 | 167 | 170 | 173 | 176 | 179 | 182 | 185 | 189 | 190 | 200 | 204 | 207 | 210 | 213 | 216 | 226 | 229 | 232 | 235 | 250 | 253 | 256 | 259 | 262 | 265 | 268 | 271 | 275 | 276 | 286 | 290 | 293 | 296 | 299 | 303 | 313 | 316 | 319 | 322 | 337 | 340 | 343 | 346 | 349 | 352 | 355 | 358 | 362 | 363 | 373 | 377 | 380 | 383 | 386 | 389 | 399 | 402 | 405 | 408 | 423 | 426 | 429 | 432 | 435 | 438 | 441 | 444 | 448 | 449 | 459 | 463 | 466 | 469 | 472 | 476 | 486 | 489 | 492 | 495 | 510 | 513 | 516 | 519 | 522 | 525 | 528 | 531 | 535 | 536 | 546 | 550 | 553 | 556 | 559 | 562 | 572 | 575 | 578 | 581 | 596 | 599 | 602 | 605 | 608 | 611 | 614 | 617 | 621 | 622 | 632 | 636 | 639 | 642 | 645 | 649 | 659 | 662 | 665 | 668 | 683 | 686 | 689 | 692 | 695 | 698 | 701 | 704 | 708 | 709 | 719 | 723 | 726 | 729 | 732 | 735 | 745 | 748 | 751 | 754 | 769 | 772 | 775 | 778 | 781 | 784 | 787 | 790 | 794 | 795 | 805 | 809 | 812 | 815 | 818 | 822 | 832 | 835 | 838 | 841 | 856 | 859 | 862 | 865 | 868 | 871 | 874 | 877 | 881 | 882 | 892 | 896 | 899 | 902 | 905 | 908 | 918 | 921 | 924 | 927 | 942 | 945 | 948 | 951 | 954 | 957 | 960 | 963 | 967 | 968 | 978 | 982 | 985 | 988 | 991 | 995 | 1005 | 1008 | 1011 | 1014 | 1029 | 1032 | 1035 | 1038 | 1041 | 1044 | 1047 | 1050 | 1054 | 1055 | 1062 | 1066 | 1069 | 1072 | 1075 | 1078 | 1091 | 1094 | 1097 | 1100 | 1113 | 1116 | 1119 | 1122 | 1125 | 1128 | 1131 | 1134 | 1138 | 1139 | 1147 | 1151 | 1154 | 1157 | 1160 | 1164 | 1177 | 1180 | 1183 | 1186 | 1200 | 1203 | 1206 | 1209 | 1212 | 1215 | 1218 | 1221 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1233 | 1236 | 1237 | 1240 | 1241 | 1244 | 1245 | 1248 | 1249 | 1250 | 1253 | 1256 | 1257 | 1260 | 1261 | 1264 | 1265 | 1268 | 1269 | 1270 | 1273 | 1274 | 1277 | 1278 | 1281 | 1282 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | -------------------------------------------------------------------------------- /blurPython_msvc2008.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blurPython_msvc2008", "blurPython_msvc2008.vcproj", "{78FEBC09-C6EB-4D5F-A7A2-6D580847783E}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Max2010_Python24|Win32 = Max2010_Python24|Win32 11 | Max2010_Python24|x64 = Max2010_Python24|x64 12 | Max2010_Python27|Win32 = Max2010_Python27|Win32 13 | Max2010_Python27|x64 = Max2010_Python27|x64 14 | Max2010x64_Python26_hybrid|Win32 = Max2010x64_Python26_hybrid|Win32 15 | Max2010x64_Python26_hybrid|x64 = Max2010x64_Python26_hybrid|x64 16 | Max2010x64_Python26|Win32 = Max2010x64_Python26|Win32 17 | Max2010x64_Python26|x64 = Max2010x64_Python26|x64 18 | Max2010x64_Python27|Win32 = Max2010x64_Python27|Win32 19 | Max2010x64_Python27|x64 = Max2010x64_Python27|x64 20 | Max2012|Win32 = Max2012|Win32 21 | Max2012|x64 = Max2012|x64 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Debug|Win32.ActiveCfg = Max2010_Python24|x64 25 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Debug|x64.ActiveCfg = Max2010_Python24|x64 26 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Debug|x64.Build.0 = Max2010_Python24|x64 27 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010_Python24|Win32.ActiveCfg = Max2010_Python24|Win32 28 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010_Python24|Win32.Build.0 = Max2010_Python24|Win32 29 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010_Python24|x64.ActiveCfg = Max2010_Python24|x64 30 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010_Python27|Win32.ActiveCfg = Max2010_Python27|Win32 31 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010_Python27|Win32.Build.0 = Max2010_Python27|Win32 32 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010_Python27|x64.ActiveCfg = Max2010_Python27|x64 33 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010_Python27|x64.Build.0 = Max2010_Python27|x64 34 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python26_hybrid|Win32.ActiveCfg = Max2010x64_Python26_hybrid|Win32 35 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python26_hybrid|x64.ActiveCfg = Max2010x64_Python26_hybrid|x64 36 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python26_hybrid|x64.Build.0 = Max2010x64_Python26_hybrid|x64 37 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python26|Win32.ActiveCfg = Max2010x64_Python26|Win32 38 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python26|Win32.Build.0 = Max2010x64_Python26|Win32 39 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python26|x64.ActiveCfg = Max2010x64_Python26|x64 40 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python26|x64.Build.0 = Max2010x64_Python26|x64 41 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python27|Win32.ActiveCfg = Max2010x64_Python27|Win32 42 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python27|Win32.Build.0 = Max2010x64_Python27|Win32 43 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python27|x64.ActiveCfg = Max2010x64_Python27|x64 44 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2010x64_Python27|x64.Build.0 = Max2010x64_Python27|x64 45 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012|Win32.ActiveCfg = Max2012|Win32 46 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012|Win32.Build.0 = Max2012|Win32 47 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012|x64.ActiveCfg = Max2012|x64 48 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012|x64.Build.0 = Max2012|x64 49 | EndGlobalSection 50 | GlobalSection(SolutionProperties) = preSolution 51 | HideSolutionNode = FALSE 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /blurPython_msvc2008.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 32 | 36 | 39 | 42 | 45 | 48 | 58 | 61 | 64 | 67 | 84 | 87 | 90 | 93 | 96 | 99 | 102 | 106 | 107 | 113 | 117 | 120 | 123 | 126 | 129 | 138 | 141 | 144 | 147 | 162 | 165 | 168 | 171 | 174 | 177 | 180 | 183 | 184 | 194 | 198 | 201 | 204 | 207 | 210 | 225 | 228 | 231 | 234 | 251 | 254 | 257 | 260 | 263 | 266 | 269 | 273 | 274 | 280 | 284 | 287 | 290 | 293 | 296 | 301 | 304 | 307 | 310 | 317 | 320 | 323 | 326 | 329 | 332 | 335 | 338 | 339 | 349 | 353 | 356 | 359 | 362 | 365 | 375 | 378 | 381 | 384 | 401 | 404 | 407 | 410 | 413 | 416 | 419 | 423 | 424 | 430 | 434 | 437 | 440 | 443 | 447 | 457 | 460 | 463 | 466 | 481 | 484 | 487 | 490 | 493 | 496 | 499 | 503 | 504 | 514 | 518 | 521 | 524 | 527 | 530 | 545 | 548 | 551 | 554 | 571 | 574 | 577 | 580 | 583 | 586 | 589 | 593 | 594 | 600 | 604 | 607 | 610 | 613 | 617 | 622 | 625 | 628 | 631 | 639 | 642 | 645 | 648 | 651 | 654 | 657 | 660 | 661 | 671 | 675 | 678 | 681 | 684 | 687 | 697 | 700 | 703 | 706 | 723 | 726 | 729 | 732 | 735 | 738 | 741 | 745 | 746 | 752 | 756 | 759 | 762 | 765 | 769 | 778 | 781 | 784 | 787 | 802 | 805 | 808 | 811 | 814 | 817 | 820 | 823 | 824 | 828 | 831 | 834 | 837 | 840 | 843 | 846 | 849 | 852 | 855 | 858 | 861 | 864 | 867 | 870 | 873 | 876 | 879 | 880 | 886 | 889 | 892 | 895 | 898 | 901 | 906 | 909 | 912 | 915 | 922 | 925 | 928 | 931 | 934 | 937 | 940 | 943 | 944 | 945 | 946 | 947 | 948 | 951 | 954 | 955 | 958 | 959 | 962 | 963 | 966 | 967 | 968 | 971 | 974 | 975 | 978 | 979 | 982 | 983 | 986 | 987 | 988 | 991 | 992 | 995 | 996 | 999 | 1000 | 1003 | 1004 | 1007 | 1008 | 1011 | 1012 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | -------------------------------------------------------------------------------- /blurPython_msvc2010.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 11.00 2 | # Visual Studio 2010 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blurPython", "blurPython_msvc2010.vcxproj", "{78FEBC09-C6EB-4D5F-A7A2-6D580847783E}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Max2012_Python24|Win32 = Max2012_Python24|Win32 8 | Max2012_Python24|x64 = Max2012_Python24|x64 9 | Max2012_Python27|Win32 = Max2012_Python27|Win32 10 | Max2012_Python27|x64 = Max2012_Python27|x64 11 | Max2012x64_Python26|Win32 = Max2012x64_Python26|Win32 12 | Max2012x64_Python26|x64 = Max2012x64_Python26|x64 13 | Max2013_Python27|Win32 = Max2013_Python27|Win32 14 | Max2013_Python27|x64 = Max2013_Python27|x64 15 | Max2014_Python27|Win32 = Max2014_Python27|Win32 16 | Max2014_Python27|x64 = Max2014_Python27|x64 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python24|Win32.ActiveCfg = Max2012_Python24|x64 20 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python24|x64.ActiveCfg = Max2012_Python24|x64 21 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python24|x64.Build.0 = Max2012_Python24|x64 22 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python27|Win32.ActiveCfg = Max2012_Python24|x64 23 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python27|x64.ActiveCfg = Max2012_Python24|x64 24 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python27|x64.Build.0 = Max2012_Python24|x64 25 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26|Win32.ActiveCfg = Max2012x64_Python26|x64 26 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26|x64.ActiveCfg = Max2012x64_Python26|x64 27 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26|x64.Build.0 = Max2012x64_Python26|x64 28 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013_Python27|Win32.ActiveCfg = Max2013x32_Python27|Win32 29 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013_Python27|Win32.Build.0 = Max2013x32_Python27|Win32 30 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013_Python27|x64.ActiveCfg = Max2013x64_Python27|x64 31 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013_Python27|x64.Build.0 = Max2013x64_Python27|x64 32 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|Win32.ActiveCfg = Max2014_Python27|Win32 33 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|Win32.Build.0 = Max2014_Python27|Win32 34 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|x64.ActiveCfg = Max2014_Python27|x64 35 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|x64.Build.0 = Max2014_Python27|x64 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /blurPython_msvc2010.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 32 | 36 | 39 | 42 | 45 | 48 | 58 | 61 | 64 | 67 | 84 | 87 | 90 | 93 | 96 | 99 | 102 | 106 | 107 | 113 | 117 | 120 | 123 | 126 | 129 | 138 | 141 | 144 | 147 | 162 | 165 | 168 | 171 | 174 | 177 | 180 | 183 | 184 | 194 | 198 | 201 | 204 | 207 | 210 | 225 | 228 | 231 | 234 | 251 | 254 | 257 | 260 | 263 | 266 | 269 | 273 | 274 | 280 | 284 | 287 | 290 | 293 | 296 | 301 | 304 | 307 | 310 | 317 | 320 | 323 | 326 | 329 | 332 | 335 | 338 | 339 | 349 | 353 | 356 | 359 | 362 | 365 | 375 | 378 | 381 | 384 | 401 | 404 | 407 | 410 | 413 | 416 | 419 | 423 | 424 | 430 | 434 | 437 | 440 | 443 | 447 | 457 | 460 | 463 | 466 | 481 | 484 | 487 | 490 | 493 | 496 | 499 | 503 | 504 | 505 | 506 | 507 | 508 | 511 | 514 | 515 | 518 | 519 | 522 | 523 | 526 | 527 | 528 | 531 | 534 | 535 | 538 | 539 | 542 | 543 | 546 | 547 | 548 | 551 | 552 | 555 | 556 | 559 | 560 | 563 | 564 | 567 | 568 | 571 | 572 | 575 | 576 | 577 | 578 | 579 | 580 | -------------------------------------------------------------------------------- /blurPython_msvc2010.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {26fb4397-79b6-4a98-b38c-e28e3e24aca9} 6 | 7 | 8 | {a3fc0823-cdc8-4ec0-b969-58243c19c036} 9 | 10 | 11 | 12 | 13 | include 14 | 15 | 16 | include 17 | 18 | 19 | include 20 | 21 | 22 | include 23 | 24 | 25 | 26 | 27 | 28 | src 29 | 30 | 31 | src 32 | 33 | 34 | src 35 | 36 | 37 | src 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /blurPython_msvc2012.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blurPython", "blurPython_msvc2012.vcxproj", "{78FEBC09-C6EB-4D5F-A7A2-6D580847783E}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Max2012_Python24|Win32 = Max2012_Python24|Win32 9 | Max2012_Python24|x64 = Max2012_Python24|x64 10 | Max2012x64_Python26_hybrid|Win32 = Max2012x64_Python26_hybrid|Win32 11 | Max2012x64_Python26_hybrid|x64 = Max2012x64_Python26_hybrid|x64 12 | Max2012x64_Python26|Win32 = Max2012x64_Python26|Win32 13 | Max2012x64_Python26|x64 = Max2012x64_Python26|x64 14 | Max2012x64_Python27|Win32 = Max2012x64_Python27|Win32 15 | Max2012x64_Python27|x64 = Max2012x64_Python27|x64 16 | Max2013x32_Python27|Win32 = Max2013x32_Python27|Win32 17 | Max2013x32_Python27|x64 = Max2013x32_Python27|x64 18 | Max2013x64_Python27|Win32 = Max2013x64_Python27|Win32 19 | Max2013x64_Python27|x64 = Max2013x64_Python27|x64 20 | Max2014_Python27|Win32 = Max2014_Python27|Win32 21 | Max2014_Python27|x64 = Max2014_Python27|x64 22 | Max2015_Python27|Win32 = Max2015_Python27|Win32 23 | Max2015_Python27|x64 = Max2015_Python27|x64 24 | Max2016_Python27|Win32 = Max2016_Python27|Win32 25 | Max2016_Python27|x64 = Max2016_Python27|x64 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python24|Win32.ActiveCfg = Max2012_Python24|Win32 29 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python24|Win32.Build.0 = Max2012_Python24|Win32 30 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python24|x64.ActiveCfg = Max2012_Python24|x64 31 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012_Python24|x64.Build.0 = Max2012_Python24|x64 32 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26_hybrid|Win32.ActiveCfg = Max2012x64_Python26_hybrid|Win32 33 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26_hybrid|Win32.Build.0 = Max2012x64_Python26_hybrid|Win32 34 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26_hybrid|x64.ActiveCfg = Max2012x64_Python26_hybrid|x64 35 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26_hybrid|x64.Build.0 = Max2012x64_Python26_hybrid|x64 36 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26|Win32.ActiveCfg = Max2012x64_Python26|Win32 37 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26|Win32.Build.0 = Max2012x64_Python26|Win32 38 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26|x64.ActiveCfg = Max2012x64_Python26|x64 39 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python26|x64.Build.0 = Max2012x64_Python26|x64 40 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python27|Win32.ActiveCfg = Max2012x64_Python27|Win32 41 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python27|Win32.Build.0 = Max2012x64_Python27|Win32 42 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python27|x64.ActiveCfg = Max2012x64_Python27|x64 43 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2012x64_Python27|x64.Build.0 = Max2012x64_Python27|x64 44 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x32_Python27|Win32.ActiveCfg = Max2013x32_Python27|Win32 45 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x32_Python27|Win32.Build.0 = Max2013x32_Python27|Win32 46 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x32_Python27|x64.ActiveCfg = Max2013x32_Python27|x64 47 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x32_Python27|x64.Build.0 = Max2013x32_Python27|x64 48 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x64_Python27|Win32.ActiveCfg = Max2013x64_Python27|Win32 49 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x64_Python27|Win32.Build.0 = Max2013x64_Python27|Win32 50 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x64_Python27|x64.ActiveCfg = Max2013x64_Python27|x64 51 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2013x64_Python27|x64.Build.0 = Max2013x64_Python27|x64 52 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|Win32.ActiveCfg = Max2014_Python27|Win32 53 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|Win32.Build.0 = Max2014_Python27|Win32 54 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|x64.ActiveCfg = Max2014_Python27|x64 55 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2014_Python27|x64.Build.0 = Max2014_Python27|x64 56 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2015_Python27|Win32.ActiveCfg = Max2015_Python27|Win32 57 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2015_Python27|Win32.Build.0 = Max2015_Python27|Win32 58 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2015_Python27|x64.ActiveCfg = Max2015_Python27|x64 59 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2015_Python27|x64.Build.0 = Max2015_Python27|x64 60 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2016_Python27|Win32.ActiveCfg = Max2016_Python27|Win32 61 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2016_Python27|Win32.Build.0 = Max2016_Python27|Win32 62 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2016_Python27|x64.ActiveCfg = Max2016_Python27|x64 63 | {78FEBC09-C6EB-4D5F-A7A2-6D580847783E}.Max2016_Python27|x64.Build.0 = Max2016_Python27|x64 64 | EndGlobalSection 65 | GlobalSection(SolutionProperties) = preSolution 66 | HideSolutionNode = FALSE 67 | EndGlobalSection 68 | EndGlobal 69 | -------------------------------------------------------------------------------- /blurPython_msvc2012.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | src 7 | 8 | 9 | src 10 | 11 | 12 | src 13 | 14 | 15 | src 16 | 17 | 18 | 19 | 20 | 21 | include 22 | 23 | 24 | include 25 | 26 | 27 | include 28 | 29 | 30 | include 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | {c1a7cf2a-f3e9-4773-b94d-30d2372b9a4f} 45 | 46 | 47 | {888938ad-13af-47be-a630-23d6e94005e5} 48 | 49 | 50 | -------------------------------------------------------------------------------- /buildVersion.py: -------------------------------------------------------------------------------- 1 | ## 2 | # :namespace buildVersion 3 | # 4 | # :remarks Queries git for version specific info and automaticly generates version.h 5 | # 6 | # :author mikeh@blur.com 7 | # :author Blur Studio 8 | # :date 05/11/15 9 | # 10 | 11 | import sys 12 | import re 13 | import datetime 14 | from subprocess import Popen, PIPE 15 | 16 | def interrogateGit(arguments, regex): 17 | p = Popen(arguments, stdout=PIPE) 18 | ret, err = p.communicate() 19 | if err: 20 | sys.exit(err) 21 | match = re.match(regex, ret) 22 | if not match: 23 | print 'Unable to find match' 24 | print [ret] 25 | print regex 26 | sys.exit(2) 27 | return match 28 | 29 | gitVersion = interrogateGit( 30 | ['git', 'describe', '--long'], 31 | r'v(?P\d+).(?P\d+).(?P\d+)-\d+-(?P[\w]+)' 32 | ) 33 | 34 | data = gitVersion.groupdict() 35 | 36 | revCount = interrogateGit(['git', 'rev-list', 'HEAD', '--count'], r'\d+') 37 | data['revCount'] = revCount.group(0) 38 | 39 | time = datetime.datetime.now() 40 | data['datetime'] = time.strftime('%Y/%m/%d %H:%M:%S') 41 | 42 | with open('version_h_template.txt') as r: 43 | text = r.read() 44 | with open('version.h', 'w') as v: 45 | output = text.format(**data) 46 | v.write(output) 47 | 48 | sys.exit(0) -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=C:\Python26_64\python.exe C:\Python26_64\Scripts\sphinx-build-script.py 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | if NOT "%PAPER%" == "" ( 11 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 12 | ) 13 | 14 | if "%1" == "" goto help 15 | 16 | if "%1" == "help" ( 17 | :help 18 | echo.Please use `make ^` where ^ is one of 19 | echo. html to make standalone HTML files 20 | echo. dirhtml to make HTML files named index.html in directories 21 | echo. singlehtml to make a single large HTML file 22 | echo. pickle to make pickle files 23 | echo. json to make JSON files 24 | echo. htmlhelp to make HTML files and a HTML help project 25 | echo. qthelp to make HTML files and a qthelp project 26 | echo. devhelp to make HTML files and a Devhelp project 27 | echo. epub to make an epub 28 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 29 | echo. text to make text files 30 | echo. man to make manual pages 31 | echo. changes to make an overview over all changed/added/deprecated items 32 | echo. linkcheck to check all external links for integrity 33 | echo. doctest to run all doctests embedded in the documentation if enabled 34 | goto end 35 | ) 36 | 37 | if "%1" == "clean" ( 38 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 39 | del /q /s %BUILDDIR%\* 40 | goto end 41 | ) 42 | 43 | if "%1" == "html" ( 44 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 45 | if errorlevel 1 exit /b 1 46 | echo. 47 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 48 | goto end 49 | ) 50 | 51 | if "%1" == "dirhtml" ( 52 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 53 | if errorlevel 1 exit /b 1 54 | echo. 55 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 56 | goto end 57 | ) 58 | 59 | if "%1" == "singlehtml" ( 60 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 61 | if errorlevel 1 exit /b 1 62 | echo. 63 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 64 | goto end 65 | ) 66 | 67 | if "%1" == "pickle" ( 68 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 69 | if errorlevel 1 exit /b 1 70 | echo. 71 | echo.Build finished; now you can process the pickle files. 72 | goto end 73 | ) 74 | 75 | if "%1" == "json" ( 76 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished; now you can process the JSON files. 80 | goto end 81 | ) 82 | 83 | if "%1" == "htmlhelp" ( 84 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished; now you can run HTML Help Workshop with the ^ 88 | .hhp project file in %BUILDDIR%/htmlhelp. 89 | goto end 90 | ) 91 | 92 | if "%1" == "qthelp" ( 93 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 94 | if errorlevel 1 exit /b 1 95 | echo. 96 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 97 | .qhcp project file in %BUILDDIR%/qthelp, like this: 98 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\trax.qhcp 99 | echo.To view the help file: 100 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\trax.ghc 101 | goto end 102 | ) 103 | 104 | if "%1" == "devhelp" ( 105 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 106 | if errorlevel 1 exit /b 1 107 | echo. 108 | echo.Build finished. 109 | goto end 110 | ) 111 | 112 | if "%1" == "epub" ( 113 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 117 | goto end 118 | ) 119 | 120 | if "%1" == "latex" ( 121 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 122 | if errorlevel 1 exit /b 1 123 | echo. 124 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 125 | goto end 126 | ) 127 | 128 | if "%1" == "text" ( 129 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 130 | if errorlevel 1 exit /b 1 131 | echo. 132 | echo.Build finished. The text files are in %BUILDDIR%/text. 133 | goto end 134 | ) 135 | 136 | if "%1" == "man" ( 137 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 141 | goto end 142 | ) 143 | 144 | if "%1" == "changes" ( 145 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.The overview file is in %BUILDDIR%/changes. 149 | goto end 150 | ) 151 | 152 | if "%1" == "linkcheck" ( 153 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Link check complete; look for any errors in the above output ^ 157 | or in %BUILDDIR%/linkcheck/output.txt. 158 | goto end 159 | ) 160 | 161 | if "%1" == "doctest" ( 162 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 163 | if errorlevel 1 exit /b 1 164 | echo. 165 | echo.Testing of doctests in the sources finished, look at the ^ 166 | results in %BUILDDIR%/doctest/output.txt. 167 | goto end 168 | ) 169 | 170 | :end 171 | -------------------------------------------------------------------------------- /docs/source/_static/blur.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blurstudio/Py3dsMax/0f59c3e0e398ebee592a7d69ffe8ef632e0c9b0d/docs/source/_static/blur.ico -------------------------------------------------------------------------------- /docs/source/_static/blur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blurstudio/Py3dsMax/0f59c3e0e398ebee592a7d69ffe8ef632e0c9b0d/docs/source/_static/blur.png -------------------------------------------------------------------------------- /docs/source/_static/blur_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blurstudio/Py3dsMax/0f59c3e0e398ebee592a7d69ffe8ef632e0c9b0d/docs/source/_static/blur_large.png -------------------------------------------------------------------------------- /docs/source/_static/blursphinx.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* ---- Navigation Bar -------------------------------------------- */ 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/source/_templates/__static/blur.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blurstudio/Py3dsMax/0f59c3e0e398ebee592a7d69ffe8ef632e0c9b0d/docs/source/_templates/__static/blur.ico -------------------------------------------------------------------------------- /docs/source/_templates/__static/blur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blurstudio/Py3dsMax/0f59c3e0e398ebee592a7d69ffe8ef632e0c9b0d/docs/source/_templates/__static/blur.png -------------------------------------------------------------------------------- /docs/source/_templates/__static/blur_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blurstudio/Py3dsMax/0f59c3e0e398ebee592a7d69ffe8ef632e0c9b0d/docs/source/_templates/__static/blur_large.png -------------------------------------------------------------------------------- /docs/source/_templates/indexcontent.html: -------------------------------------------------------------------------------- 1 | 2 | {% extends "defindex.html" %} 3 | {% block tables %} 4 |

Parts of the documentation:

5 | 6 | 14 |
7 | 9 | 13 |
15 | 16 | 17 |

Indices and tables:

18 | 19 | 27 |
20 | 22 | 24 | 26 |
28 | 29 | 30 |

Meta information:

31 | 32 | 39 |
33 | 34 | 35 | 38 |
40 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /docs/source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% extends "!layout.html" %} 4 | 5 | {% block rootrellink %} 6 |
  • 9 |
  • Blur Docs{{ reldelim1 }}
  • 10 | 11 |
  • {{ shorttitle }}{{ reldelim1 }}
  • 12 | {% endblock %} 13 | {% block extrahead %} 14 | 15 | 16 | {{ super() }} 17 | {% endblock %} 18 | {% block footer %} 19 | 27 | {% endblock %} 28 | {% block sidebarsourcelink %} 29 | {%- if show_source and has_source and sourcename %} 30 |

    {{ _('This Page') }}

    31 | 36 | {%- endif %} 37 | {% endblock %} 38 | 39 | 40 | 41 | {% raw %} 42 | 43 | 44 | 45 | 46 | 47 | 50 | 53 | 54 | {{=response.title or request.application}} 55 | 56 | 57 | 58 | 59 | 61 | 62 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | 75 | 76 | 77 | 78 | {{ 79 | response.files.append(URL('static','css/bootstrap.min.css')) 80 | response.files.append(URL('static','css/bootstrap-responsive.min.css')) 81 | response.files.append(URL('static','css/web2py.css')) 82 | response.files.append(URL('static','css/web2py_bootstrap.css')) 83 | }} 84 | 85 | {{include 'web2py_ajax.html'}} 86 | 87 | {{ 88 | # using sidebars need to know what sidebar you want to use 89 | left_sidebar_enabled = globals().get('left_sidebar_enabled',False) 90 | right_sidebar_enabled = globals().get('right_sidebar_enabled',False) 91 | middle_columns = {0:'span12',1:'span9',2:'span6'}[ 92 | (left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)] 93 | }} 94 | 95 | 99 | 100 | {{block head}}{{end}} 101 | 102 | 103 | 104 | 105 | 125 | 126 |
    127 |
    {{=response.flash or ''}}
    128 | 129 | 130 | 140 | 141 |
    142 |
    143 | {{if left_sidebar_enabled:}} 144 | 150 | {{pass}} 151 | 152 |
    153 | {{block center}} 154 | {{include}} 155 | {{end}} 156 |
    157 | 158 | {{if right_sidebar_enabled:}} 159 |
    160 | {{block right_sidebar}} 161 |

    Right Sidebar

    162 |

    163 | {{end}} 164 |
    165 | {{pass}} 166 |
    167 |
    168 | 169 | 170 |
    171 | {{block footer}} 172 | 179 | {{end}} 180 |
    181 | 182 |
    183 | 184 | 186 | 207 | 208 | 212 | {{if response.google_analytics_id:}} {{pass}} 213 | 214 | 215 | 216 | {% endraw %} 217 | 218 | 219 | -------------------------------------------------------------------------------- /docs/source/bugs.rst: -------------------------------------------------------------------------------- 1 | .. _reporting-bugs: 2 | 3 | ************** 4 | Reporting Bugs 5 | ************** 6 | 7 | If you think you've found a bug, try asking about it on codefoo@blur.com. 8 | It's possible that the bug has been fixed in a dev build, or that it's a known 9 | issue, or perhaps it's even expected bahavior. 10 | 11 | You can also create a 12 | `new bug `_ 13 | report in redmine. 14 | 15 | 16 | .. seealso:: 17 | 18 | `How to Report Bugs Effectively `_ 19 | Article which goes into some detail about how to create a useful bug report. 20 | This describes what kind of information is useful and why it is useful. 21 | 22 | `Bug Writing Guidelines `_ 23 | Information about writing a good bug report. Some of this is specific to the 24 | Mozilla project, but describes general good practices. 25 | 26 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # trax documentation build configuration file, created by 4 | # sphinx-quickstart on Wed Mar 16 12:32:45 2011. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 29 | 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 30 | 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode'] 31 | 32 | # Add any paths that contain templates here, relative to this directory. 33 | templates_path = ['_templates'] 34 | 35 | # The suffix of source filenames. 36 | source_suffix = '.rst' 37 | 38 | # The encoding of source files. 39 | #source_encoding = 'utf-8-sig' 40 | 41 | # The master toctree document. 42 | #master_doc = 'index' 43 | 44 | # General information about the project. 45 | project = u'Py3dsMax' 46 | copyright = u'2012, Blur' 47 | 48 | # The version info for the project you're documenting, acts as replacement for 49 | # |version| and |release|, also used in various other places throughout the 50 | # built documents. 51 | # 52 | # The short X.Y version. 53 | version = '1.0' 54 | # The full version, including alpha/beta/rc tags. 55 | release = '1.0' 56 | 57 | # The language for content autogenerated by Sphinx. Refer to documentation 58 | # for a list of supported languages. 59 | #language = None 60 | 61 | # There are two options for replacing |today|: either, you set today to some 62 | # non-false value, then it is used: 63 | today = '' 64 | # Else, today_fmt is used as the format for a strftime call. 65 | today_fmt = '%B %d, %Y' 66 | 67 | # List of patterns, relative to source directory, that match files and 68 | # directories to ignore when looking for source files. 69 | exclude_patterns = [] 70 | 71 | # The reST default role (used for this markup: `text`) to use for all documents. 72 | #default_role = None 73 | 74 | # If true, '()' will be appended to :func: etc. cross-reference text. 75 | add_function_parentheses = True 76 | 77 | # If true, the current module name will be prepended to all description 78 | # unit titles (such as .. function::). 79 | add_module_names = True 80 | 81 | # If true, sectionauthor and moduleauthor directives will be shown in the 82 | # output. They are ignored by default. 83 | #show_authors = False 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'sphinx' 87 | 88 | # A list of ignored prefixes for module index sorting. 89 | #modindex_common_prefix = [] 90 | 91 | 92 | # -- Options for HTML output --------------------------------------------------- 93 | 94 | # The theme to use for HTML and HTML Help pages. See the documentation for 95 | # a list of builtin themes. 96 | html_theme = 'default' 97 | 98 | # Theme options are theme-specific and customize the look and feel of a theme 99 | # further. For a list of options available for each theme, see the 100 | # documentation. 101 | #html_theme_options = {} 102 | html_theme_options = { 103 | # 'stickysidebar': 'true', 104 | } 105 | 106 | # Add any paths that contain custom themes here, relative to this directory. 107 | #html_theme_path = [] 108 | 109 | # The name for this set of Sphinx documents. If None, it defaults to 110 | # " v documentation". 111 | html_title = "%s v%s" % (project, release) 112 | 113 | # A shorter title for the navigation bar. Default is the same as html_title. 114 | #html_short_title = None 115 | 116 | # The name of an image file (relative to this directory) to place at the top 117 | # of the sidebar. 118 | html_logo = '_static/blur.png' 119 | 120 | # The name of an image file (within the static path) to use as favicon of the 121 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 122 | # pixels large. 123 | html_favicon = '_static/blur.ico' 124 | 125 | # Add any paths that contain custom static files (such as style sheets) here, 126 | # relative to this directory. They are copied after the builtin static files, 127 | # so a file named "default.css" will overwrite the builtin "default.css". 128 | html_static_path = ['_static'] 129 | 130 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 131 | # using the given strftime format. 132 | html_last_updated_fmt = '%b %d, %Y' 133 | 134 | # If true, SmartyPants will be used to convert quotes and dashes to 135 | # typographically correct entities. 136 | html_use_smartypants = True 137 | 138 | # Custom sidebar templates, maps document names to template names. 139 | ##html_sidebars = { 140 | ## 'index': 'indexsidebar.html', 141 | ##} 142 | 143 | # Additional templates that should be rendered to pages, maps page names to 144 | # template names. 145 | html_additional_pages = { 146 | 'index': 'indexcontent.html', 147 | } 148 | 149 | # If false, no module index is generated. 150 | #html_domain_indices = True 151 | 152 | # If false, no index is generated. 153 | #html_use_index = True 154 | 155 | # If true, the index is split into individual pages for each letter. 156 | #html_split_index = False 157 | 158 | # If true, links to the reST sources are added to the pages. 159 | html_show_sourcelink = True 160 | 161 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 162 | html_show_sphinx = True 163 | 164 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 165 | html_show_copyright = True 166 | 167 | # If true, an OpenSearch description file will be output, and all pages will 168 | # contain a tag referring to it. The value of this option must be the 169 | # base URL from which the finished HTML is served. 170 | #html_use_opensearch = '' 171 | 172 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 173 | #html_file_suffix = None 174 | 175 | # Output file base name for HTML help builder. 176 | htmlhelp_basename = project 177 | 178 | 179 | # Example configuration for intersphinx: refer to the Python standard library. 180 | intersphinx_mapping = {'http://docs.python.org/': None} 181 | -------------------------------------------------------------------------------- /docs/source/contents.rst: -------------------------------------------------------------------------------- 1 | ###################### 2 | Blurdev Contents 3 | ###################### 4 | 5 | .. toctree:: 6 | 7 | tutorial/index.rst 8 | reference/index.rst 9 | bugs.rst 10 | copyright.rst 11 | 12 | -------------------------------------------------------------------------------- /docs/source/copyright.rst: -------------------------------------------------------------------------------- 1 | ********* 2 | Copyright 3 | ********* 4 | 5 | This software and documentation are: 6 | 7 | Copyright © 2012 Blur 8 | 9 | -------------------------------------------------------------------------------- /docs/source/rst_maker.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import os 4 | import subprocess 5 | 6 | 7 | def main(): 8 | call_children() 9 | 10 | 11 | def call_children(): 12 | rootdir = os.path.normpath(os.path.dirname(os.path.abspath(__file__))) 13 | for root, dirnames, filenames in os.walk(rootdir): 14 | if root == rootdir: 15 | continue 16 | for fn in filenames: 17 | if fn == 'rst_maker.py': 18 | fp = os.path.join(root, fn) 19 | subprocess.call('python "%s"' % fp) 20 | 21 | 22 | if __name__ == '__main__': 23 | main() 24 | -------------------------------------------------------------------------------- /docs/source/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-index: 2 | 3 | ################################# 4 | The Py3dsMax Tutorial 5 | ################################# 6 | 7 | What is Py3dsMax? 8 | ================= 9 | 10 | Py3dsMax is a Max plugin that embeds python within Max. This allows python 11 | scripts to run natively within the Max environment. It allows maxscript 12 | commands to be called from python; and conversely, python commands to be 13 | called from maxscript. 14 | 15 | 16 | Why python? 17 | ================= 18 | 19 | Python is arguably the most popular scripting language, especially amongst 3D 20 | applications. Many 3D apps already support python natively. There is a large 21 | community of python develepers, and in addition to a large standard library, 22 | there is an even larger collection of 3rd party python libraries for nearly 23 | every purpose. Py3dsMax allows Max developers to leverage that vast python 24 | codebase. 25 | 26 | 27 | What if I can't find what I'm looking for? 28 | ========================================== 29 | 30 | Send an email to codefoo@blur.com with any questions or reports of areas of 31 | blurdev that need better documentation. Or better yet, you could try creating 32 | the documentation yourself. We always need more help writing and maintaining 33 | documentation. 34 | 35 | 36 | 37 | 38 | Indices and tables 39 | ================== 40 | 41 | * :ref:`genindex` 42 | * :ref:`search` 43 | -------------------------------------------------------------------------------- /imports.h: -------------------------------------------------------------------------------- 1 | /* 2 | \file imports.h 3 | 4 | \remarks This file contains with it all the imports necessary 5 | for this plugin to compile, and in the precise order 6 | they need to be imported. 7 | 8 | \author Blur Studio (c) 2010 9 | \email beta@blur.com 10 | 11 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 12 | */ 13 | 14 | #ifndef __IMPORTS_H__ 15 | #define __IMPORTS_H__ 16 | 17 | 18 | #ifdef __MAXSCRIPT_2016__ 19 | #define __MAXSCRIPT_2015__ 20 | #endif 21 | 22 | // As of 2013 max is compiled with UNICODE enabled - MCHAR == TCHAR == wchar == Py_UNICODE, utf16 23 | #if __MAXSCRIPT_2013__ || __MAXSCRIPT_2015__ 24 | #define _UNICODE 25 | #define UNICODE 26 | #endif 27 | 28 | // max 2012 switched the name of maxscript includes 29 | #if __MAXSCRIPT_2012__ || __MAXSCRIPT_2013__ || __MAXSCRIPT_2015__ 30 | 31 | #include "foundation/numbers.h" 32 | #include "foundation/structs.h" 33 | #include "foundation/strings.h" 34 | 35 | #include "kernel/exceptions.h" 36 | #include "kernel/value.h" 37 | 38 | #include "maxwrapper/maxclasses.h" 39 | #include "maxwrapper/objectsets.h" 40 | 41 | #include "compiler/parser.h" 42 | 43 | #include "maxscript.h" 44 | #include "ScripterExport.h" 45 | 46 | // these are the includes for previous versions of 3dsmax 47 | #else 48 | 49 | #include "MAXScrpt.h" 50 | #include "Numbers.h" 51 | #include "MAXclses.h" 52 | #include "structs.h" 53 | #include "strings.h" 54 | #include "excepts.h" 55 | #include "Parser.h" 56 | #include "maxscrpt.h" 57 | #include "value.h" 58 | 59 | #endif 60 | 61 | // include python headers 62 | #include 63 | 64 | #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) 65 | typedef int Py_ssize_t; 66 | #define PY_SSIZE_T_MAX INT_MAX 67 | #define PY_SSIZE_T_MIN INT_MIN 68 | #endif 69 | 70 | #ifdef ScripterExport 71 | #undef ScripterExport 72 | #endif 73 | #define ScripterExport __declspec( dllexport ) 74 | 75 | #endif __IMPORTS_H__ -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | All of the blurPython code has been released under the GNU General Public License, and as such any use of this code must comply 2 | with the terms outlined under the GPL license. 3 | 4 | For more information regarding the GPL, please see the GNU website at: 5 | 6 | http://www.gnu.org/licenses/licenses.html#GPL -------------------------------------------------------------------------------- /macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | \file macros.h 3 | 4 | \remarks Protecting maxscript memory is a hard thing to do, and its often easy to 5 | forget the proper steps, and sometimes, easy to do it incorrectly. These macros 6 | make it a bit easier to work with. 7 | 8 | \author Blur Studio (c) 2010 9 | \email beta@blur.com 10 | 11 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 12 | 13 | */ 14 | 15 | #ifndef __MACROS_H__ 16 | #define __MACROS_H__ 17 | 18 | #include "Python.h" 19 | #include "imports.h" 20 | #include "wrapper.h" 21 | 22 | // Returns pointer to new data owned by caller 23 | MCHAR * pythonExceptionTraceback( bool clearException = true ); 24 | 25 | class PyExcRuntimeError : public RuntimeError 26 | { 27 | public: 28 | PyExcRuntimeError( MCHAR * error ); 29 | ~PyExcRuntimeError(); 30 | private: 31 | MCHAR * error; 32 | }; 33 | 34 | // Call this function to define and protect a series of values 35 | #define MXS_PROTECT( VALUE_LOCALS ) init_thread_locals(); \ 36 | push_alloc_frame(); \ 37 | VALUE_LOCALS; \ 38 | save_current_frames(); 39 | 40 | // Split a Value* from its thunk containers 41 | #define MXS_EVAL(INPUT,OUTPUT) OUTPUT = INPUT; \ 42 | while ( OUTPUT != NULL && is_thunk(OUTPUT) ) \ 43 | OUTPUT = OUTPUT->eval(); 44 | 45 | // Clear up MAXScript memory properly after an error 46 | #define MXS_CLEARERRORS() clear_error_source_data(); \ 47 | restore_current_frames(); \ 48 | MAXScript_signals = 0; 49 | 50 | // Quick macro to catch all errors, clean them, and set a MAXScript error for Python 51 | #define MXS_CATCHERRORS() catch ( ... ) { \ 52 | MXS_CLEARERRORS(); \ 53 | } 54 | 55 | // Call this macro to cleanup MAXScript memory before exiting a function 56 | #define MXS_CLEANUP() pop_value_locals(); \ 57 | pop_alloc_frame(); 58 | 59 | // Call this macro to cleanup MAXScript memory before exiting a function 60 | #define MXS_RETURN(VAL) pop_alloc_frame(); \ 61 | return_value( VAL ); 62 | 63 | #define PY_ERROR_PRINT_CLEAR \ 64 | mprintf( pythonExceptionTraceback(true) ); 65 | 66 | // Call this macro to clean up any python errors that may have occurred 67 | // TODO: Test for quiet mode 68 | #define PY_ERROR_PRINT_THROW() \ 69 | MCHAR * exc_str = pythonExceptionTraceback( /*clearException=*/ false ); \ 70 | PyErr_Print(); \ 71 | PyGILState_Release(gstate);\ 72 | throw PyExcRuntimeError( exc_str ); 73 | 74 | #define PY_ERROR_PROPAGATE() if ( PyErr_Occurred() ) { \ 75 | PY_ERROR_PRINT_THROW(); \ 76 | } 77 | 78 | #define PY_ERROR_PROPAGATE_MXS_CLEANUP() \ 79 | MXS_CLEANUP(); \ 80 | if ( PyErr_Occurred() ) { \ 81 | PY_ERROR_PRINT_THROW(); \ 82 | } 83 | 84 | #define PY_PROCESSERROR( PYEXC, MEXC ) MXS_CLEARERRORS(); \ 85 | StringStream* buffer = new StringStream("MAXScript Error Has Occurred: \n"); \ 86 | buffer->gc_trace(); \ 87 | MEXC.sprin1(buffer); \ 88 | PyErr_SetString( PYEXC, buffer->to_string() ); \ 89 | delete buffer; \ 90 | 91 | 92 | #endif __MACROS_H__ -------------------------------------------------------------------------------- /protector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | \file protector.cpp 3 | 4 | \remarks Implementation of the Protector class 5 | 6 | \author Blur Studio (c) 2010 7 | \email beta@blur.com 8 | 9 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 10 | */ 11 | 12 | #include "imports.h" 13 | 14 | #include 15 | 16 | #include "macros.h" 17 | #include "wrapper.h" 18 | #include "protector.h" 19 | 20 | visible_class_instance( Protector, "PyMemProtector" ); 21 | 22 | int Protector::mCount = 0; 23 | ValueWrapper * Protector::mFirst = 0; 24 | 25 | Protector::Protector() 26 | {} 27 | 28 | Protector::~Protector() 29 | {} 30 | 31 | Value* ProtectorClass::apply( Value** arg_list, int count, CallContext* cc ) 32 | { 33 | one_value_local( result ); 34 | vl.result = new Protector(); 35 | return_value( vl.result ); 36 | } 37 | 38 | void Protector::gc_trace() { 39 | // Step 1: trace this item 40 | Value::gc_trace(); 41 | 42 | ValueWrapper * cur = mFirst; 43 | while( cur ) { 44 | cur->mValue->gc_trace(); 45 | cur = cur->mNext; 46 | } 47 | } 48 | 49 | Value* Protector::get_property( Value** arg_list, int count ) { 50 | // return the length of the memory list 51 | if ( arg_list[0] == n_count ) { 52 | return Integer::intern( mCount ); 53 | } 54 | // dump the contents of the memory list 55 | else if ( arg_list[0] == Name::intern( _T("dump") ) ) { 56 | ValueWrapper * cur = mFirst; 57 | while( cur ) { 58 | ObjectWrapper::log((PyObject*)cur); 59 | cur = cur->mNext; 60 | } 61 | return &ok; 62 | } 63 | 64 | // return default value results for the keywords 65 | return Value::get_property( arg_list, count ); 66 | } 67 | 68 | void Protector::protect( ValueWrapper * obj ) { 69 | mCount++; 70 | obj->mNext = mFirst; 71 | obj->mPrev = 0; 72 | if( mFirst ) 73 | mFirst->mPrev = obj; 74 | mFirst = obj; 75 | } 76 | 77 | void Protector::unprotect( ValueWrapper * obj ) { 78 | mCount--; 79 | if( obj->mNext ) 80 | obj->mNext->mPrev = obj->mPrev; 81 | if( obj->mPrev ) 82 | obj->mPrev->mNext = obj->mNext; 83 | if( obj == mFirst ) 84 | mFirst = obj->mNext; 85 | } 86 | -------------------------------------------------------------------------------- /protector.h: -------------------------------------------------------------------------------- 1 | /* 2 | \file protector.h 3 | 4 | \remarks The Protector class is a Value* class that contains 5 | a list of ValueWrapper*'s that have been created to protect 6 | them during MAXScript garbage collection 7 | 8 | \author Blur Studio (c) 2010 9 | \email beta@blur.com 10 | 11 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 12 | */ 13 | 14 | #ifndef __PROTECTOR_H__ 15 | #define __PROTECTOR_H__ 16 | 17 | applyable_class( Protector ); 18 | 19 | struct ValueWrapper; 20 | 21 | class Protector : public Value { 22 | public: 23 | Protector(); 24 | ~Protector(); 25 | 26 | static Protector * sInstance; 27 | 28 | classof_methods( Protector, Value ); 29 | void collect() { delete this; } 30 | void gc_trace(); 31 | Value* get_property( Value** arg_list, int count ); 32 | 33 | static void protect( ValueWrapper * ); 34 | static void unprotect( ValueWrapper * ); 35 | 36 | protected: 37 | static int mCount; 38 | static ValueWrapper * mFirst; 39 | }; 40 | 41 | #endif __PROTECTOR_H__ -------------------------------------------------------------------------------- /python_struct.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | \file python_struct.cpp 3 | 4 | \remarks This file defines the 3dsMax struct called python 5 | 6 | \author Blur Studio (c) 2010 7 | \email beta@blur.com 8 | 9 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 10 | */ 11 | 12 | #include "imports.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | // updated to work with max 2012's new maxscript organization 24 | #if __MAXSCRIPT_2012__ || __MAXSCRIPT_2013__ || __MAXSCRIPT_2015__ 25 | 26 | #include "macros/define_external_functions.h" 27 | #include "macros/define_instantiation_functions.h" 28 | 29 | // include settings for previous versions of 3dsmax 30 | #else 31 | 32 | #include "defextfn.h" 33 | #include "definsfn.h" 34 | 35 | #endif 36 | 37 | #include "macros.h" 38 | #include "wrapper.h" 39 | 40 | // Define the python struct in 3dsMax 41 | def_struct_primitive( import, pymax, "import" ); 42 | def_struct_primitive( reload, pymax, "reload" ); 43 | def_struct_primitive( run, pymax, "run" ); 44 | def_struct_primitive( exec, pymax, "exec" ); 45 | #ifdef __MAXSCRIPT_2015__ 46 | def_struct_primitive( init, pymax, "init"); 47 | 48 | PyMODINIT_FUNC init_module(); 49 | Value* init_cf(Value** arg_list, int count) { 50 | init_module(); 51 | return &ok; 52 | } 53 | #endif 54 | 55 | // python.import function: import a python module to maxscript 56 | Value* 57 | import_cf( Value** arg_list, int count ) { 58 | PyGILState_STATE gstate; 59 | gstate = PyGILState_Ensure(); 60 | // Step 1: make sure the arguments supplied are correct 61 | check_arg_count( python.import, 1, count ); 62 | 63 | // Step 2: protect the maxscript memory 64 | MXS_PROTECT( two_value_locals( mxs_check, mxs_return ) ); 65 | 66 | // Step 3: convert the maxscript value 67 | MXS_EVAL( arg_list[0], vl.mxs_check ); 68 | 69 | // Step 4: calculate the python module name to import 70 | const MCHAR* module_name = NULL; 71 | try { module_name = vl.mxs_check->to_string(); } 72 | MXS_CATCHERRORS(); 73 | 74 | // Step 5: import the module 75 | if ( module_name ) { 76 | MCharToPyString pys(module_name); 77 | if( pys.pyString() ) { 78 | PyObject* module = PyImport_Import( pys.pyString() ); 79 | vl.mxs_return = ( module ) ? ObjectWrapper::intern( module ) : &undefined; 80 | } 81 | 82 | PY_ERROR_PROPAGATE_MXS_CLEANUP(); 83 | } 84 | else { 85 | mprintf( _T("python.import() error: importing modules must be done with a string value\n") ); 86 | vl.mxs_return = &undefined; 87 | } 88 | PyGILState_Release(gstate); 89 | MXS_RETURN( vl.mxs_return ); 90 | } 91 | 92 | // python.reload function: reload an existing module in maxscript 93 | Value* 94 | reload_cf( Value** arg_list, int count ) { 95 | // Step 1: make sure the arguments supplied are correct in count 96 | check_arg_count( python.reload, 1, count ); 97 | 98 | // Step 2: evaluate the input item 99 | MXS_PROTECT(one_value_local(mxs_check)); 100 | MXS_EVAL( arg_list[0], vl.mxs_check ); 101 | 102 | // Step 3: make sure the item is a proper type 103 | if ( is_objectwrapper(vl.mxs_check) ) { 104 | PyGILState_STATE gstate; 105 | gstate = PyGILState_Ensure(); 106 | PyImport_ReloadModule( ((ObjectWrapper*) vl.mxs_check)->object() ); 107 | PY_ERROR_PROPAGATE_MXS_CLEANUP(); 108 | PyGILState_Release(gstate); 109 | } 110 | else { mprintf( _T("python.reload() error: you need to supply a valid python module to reload\n") ); } 111 | 112 | MXS_CLEANUP(); 113 | return &ok; 114 | } 115 | 116 | // python.run function: run a python file from maxscript 117 | Value* 118 | run_cf( Value** arg_list, int count ) { 119 | // Step 1: make sure the arguments supplied are correct in count 120 | check_arg_count( python.run, 1, count ); 121 | 122 | // Step 2: protect the maxscript memory 123 | MXS_PROTECT(one_value_local(mxs_filename)); 124 | MXS_EVAL( arg_list[0], vl.mxs_filename ); 125 | 126 | // Step 2: create a python file based on the filename 127 | const MCHAR * filename = vl.mxs_filename->to_string(); 128 | //mprintf( _T("Got Filename to run: %s\n"), filename ); 129 | 130 | PyGILState_STATE gstate; 131 | gstate = PyGILState_Ensure(); 132 | MCharToPyString pys(filename); 133 | PyObject* args = PyTuple_New(2); 134 | PyTuple_SET_ITEM(args,0,pys.pyStringRef()); 135 | PyTuple_SET_ITEM(args,1,PyString_FromString("r")); 136 | //mprintf( _T("Arg tuple created, creating python file object\n") ); 137 | 138 | PyObject* py_file = PyObject_Call((PyObject*)&PyFile_Type, args, NULL); 139 | Py_DECREF(args); 140 | if( !py_file ) { 141 | mprintf( _T("Call to python file object creation failed\n") ); 142 | PY_ERROR_PROPAGATE_MXS_CLEANUP(); 143 | return &false_value; 144 | } 145 | 146 | //mprintf( _T("File opened, calling PyRun_SimpleFile\n") ); 147 | // Step 4: run the file 148 | PyRun_SimpleFile( PyFile_AsFile(py_file), pys.data() ); 149 | 150 | //mprintf( _T("File ran, cleaning up\n") ); 151 | // Step 5: cleanup the memory 152 | Py_DECREF( py_file ); 153 | PY_ERROR_PROPAGATE_MXS_CLEANUP(); 154 | PyGILState_Release(gstate); 155 | 156 | return &true_value; 157 | } 158 | 159 | // python.exec function: execute a python command through a maxscript string 160 | Value* 161 | exec_cf( Value** arg_list, int count ) { 162 | // Step 1: make sure the arguments supplied are correct in count 163 | check_arg_count( python.exec, 1, count ); 164 | 165 | // Step 2: protect the maxscript memory 166 | MXS_PROTECT(one_value_local(mxs_command)); 167 | MXS_EVAL( arg_list[0], vl.mxs_command ); 168 | 169 | // Step 2: create a python file based on the filename 170 | const MCHAR* command = NULL; 171 | try { command = vl.mxs_command->to_string(); } 172 | MXS_CATCHERRORS(); 173 | 174 | // Step 3: check to make sure the command is valid 175 | if ( !command ) { 176 | MXS_CLEANUP(); 177 | return &false_value; 178 | } 179 | 180 | { 181 | PyGILState_STATE gstate; 182 | gstate = PyGILState_Ensure(); 183 | 184 | MCharToPyString ascii(command); 185 | if( ascii.pyString() ) 186 | PyRun_SimpleString( ascii.data() ); 187 | 188 | PY_ERROR_PROPAGATE_MXS_CLEANUP(); 189 | PyGILState_Release(gstate); 190 | } 191 | 192 | // Step 5: cleanup the memory 193 | MXS_CLEANUP(); 194 | 195 | return &ok; 196 | } 197 | 198 | PyExcRuntimeError::PyExcRuntimeError( MCHAR * _error ) 199 | : RuntimeError( _error ) 200 | , error( _error ) 201 | {} 202 | 203 | PyExcRuntimeError::~PyExcRuntimeError() 204 | { 205 | delete error; 206 | } 207 | 208 | // Returns a new string 209 | MCHAR * pythonExceptionTraceback( bool clearException ) 210 | { 211 | /* 212 | import traceback 213 | return '\n'.join(traceback.format_exc()).encode('ascii','replace') 214 | */ 215 | MCHAR * ret = 0; 216 | bool success = false; 217 | 218 | PyObject * type, * value, * traceback; 219 | /* Save the current exception */ 220 | PyErr_Fetch(&type, &value, &traceback); 221 | if( type ) { 222 | 223 | PyObject * traceback_module = PyImport_ImportModule("traceback"); 224 | if (traceback_module) { 225 | 226 | /* Call the traceback module's format_exception function, which returns a list */ 227 | PyObject * traceback_list = PyObject_CallMethod(traceback_module, "format_exception", "OOO", type, value ? value : Py_None, traceback ? traceback : Py_None); 228 | if( traceback_list ) { 229 | 230 | PyObject * separator = PyString_FromString(""); 231 | if( separator ) { 232 | 233 | PyObject * retUni = PyUnicode_Join(separator, traceback_list); 234 | if( retUni ) { 235 | #ifdef UNICODE 236 | ret = _tcsdup( PyUnicode_AsUnicode(retUni) ); 237 | #else 238 | PyObject * retAscii = PyUnicode_AsEncodedString(retUni, "ascii", "replace"); 239 | if( retAscii ) { 240 | Py_ssize_t len = 0; 241 | char * tmp; 242 | if( PyString_AsStringAndSize( retAscii, &tmp, &len ) != -1 ) { 243 | ret = strdup( tmp );//, len ); 244 | success = true; 245 | } else { 246 | ret = _tcsdup( _T("Uhoh, failed to get pointer to ascii representation of the exception") ); 247 | success = false; 248 | } 249 | Py_DECREF( retAscii ); 250 | } else { 251 | ret = _tcsdup( _T("Uhoh, encoding exception to ascii failed") ); 252 | success = false; 253 | } 254 | #endif 255 | Py_DECREF(retUni); 256 | 257 | } else 258 | ret = _tcsdup(_T("PyUnicode_Join failed")); 259 | 260 | Py_DECREF(separator); 261 | } else 262 | ret = _tcsdup(_T("PyUnicode_FromString failed")); 263 | 264 | Py_DECREF(traceback_list); 265 | } else 266 | ret = _tcsdup(_T("Failure calling traceback.format_exception")); 267 | 268 | Py_DECREF(traceback_module); 269 | } else 270 | ret = _tcsdup(_T("Unable to load the traceback module, can't get exception text")); 271 | } else 272 | ret = _tcsdup(_T("pythonExceptionTraceback called, but no exception set")); 273 | 274 | if( clearException ) { 275 | Py_DECREF(type); 276 | Py_XDECREF(value); 277 | Py_XDECREF(traceback); 278 | } else 279 | PyErr_Restore(type,value,traceback); 280 | 281 | return ret; 282 | } -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by blurPython_msvc2008.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /studiomax_module.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | \file py3dsmax_module.cpp 3 | 4 | \remarks This file defines the Py3dsMax module for python, and the mxs class 5 | that can be imported from it 6 | 7 | \author Blur Studio (c) 2010 8 | \email beta@blur.com 9 | 10 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 11 | */ 12 | 13 | #include "imports.h" 14 | #include "version.h" 15 | 16 | // blurPython imports 17 | #include "macros.h" 18 | #include "wrapper.h" 19 | #include "protector.h" 20 | 21 | // define the mxs class 22 | typedef struct { 23 | PyObject_HEAD 24 | } mxs; 25 | 26 | // ctor 27 | static PyObject* 28 | mxs_new( PyTypeObject* type, PyObject* args, PyObject* kwds ) { 29 | return (PyObject*)type->tp_alloc(type, 0); 30 | } 31 | 32 | // dtor 33 | static void 34 | mxs_dealloc( PyObject* self ) { 35 | self->ob_type->tp_free(self); 36 | } 37 | 38 | // __getattr__: get an item from the maxscript globals hash table 39 | static PyObject* 40 | mxs_getattro( PyObject* self, PyObject* key ) { 41 | // Step 1: convert the key to a name 42 | //mprintf( _T("mxs_getattro entered\n") ); 43 | MXS_PROTECT(one_value_local(name)); 44 | PyStringToMCHAR mkey(key); 45 | vl.name = Name::intern( mkey.mchar() ); 46 | // Step 2: collect the PyObject* instance 47 | PyObject * output = ObjectWrapper::py_intern( globals->get( vl.name ) ); 48 | MXS_CLEANUP(); 49 | //mprintf( _T("mxs_getattro leaving\n") ); 50 | 51 | return output; 52 | } 53 | 54 | // __setattr__: set an item in the maxscript globals hash table 55 | static int 56 | mxs_setattro( PyObject* self, PyObject* key, PyObject* value ) { 57 | 58 | //mprintf( _T("mxs_setattro entered\n") ); 59 | MXS_PROTECT( two_value_locals( name, result ) ); 60 | PyStringToMCHAR mkey(key); 61 | vl.name = Name::intern( mkey.mchar() ); 62 | 63 | // Step 3: get a preexisting global value 64 | vl.result = globals->get( vl.name ); 65 | if ( vl.result ) { 66 | // Step 4: try to set the global variable 67 | try { 68 | if ( is_thunk( vl.result ) ) 69 | ((Thunk*) vl.result)->assign( ObjectWrapper::intern(value) ); 70 | else 71 | globals->set( vl.name, ObjectWrapper::intern(value) ); 72 | } 73 | MXS_CATCHERRORS(); 74 | } 75 | 76 | // Step 5: cleanup the maxscript memory 77 | MXS_CLEANUP(); 78 | //mprintf( _T("mxs_setattro leaving\n") ); 79 | 80 | return 0; 81 | } 82 | 83 | // define the mxs class 84 | static PyTypeObject MxsType = { 85 | PyObject_HEAD_INIT(NULL) 86 | 0, // ob_size 87 | "Py3dsMax.mxs", // tp_name 88 | sizeof(mxs), // tp_basicsize 89 | 0, // tp_itemsize 90 | 0, // tp_dealloc 91 | 0, // tp_print 92 | 0, // tp_getattr 93 | 0, // tp_setattr 94 | 0, // tp_compare 95 | 0, // tp_repr 96 | 0, // tp_as_number 97 | 0, // tp_as_sequence 98 | 0, // tp_as_mapping 99 | 0, // tp_hash 100 | 0, // tp_call 101 | 0, // tp_str 102 | (getattrofunc)mxs_getattro, // tp_getattro 103 | (setattrofunc)mxs_setattro, // tp_setattro 104 | 0, // tp_as_buffer 105 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags 106 | "MAXScript Globals Accessor", // tp_doc 107 | 0, // tp_traverse 108 | 0, // tp_clear 109 | 0, // tp_richcompare 110 | 0, // tp_weaklistoffset 111 | 0, // tp_iter 112 | 0, // tp_iternext 113 | 0, // tp_methods 114 | 0, // tp_members 115 | 0, // tp_getset 116 | 0, // tp_base 117 | 0, // tp_dict 118 | 0, // tp_descr_get 119 | 0, // tp_descr_set 120 | 0, // tp_dictoffset 121 | 0, // tp_init 122 | 0, // tp_alloc 123 | mxs_new, // tp_new 124 | }; 125 | 126 | 127 | typedef struct { 128 | PyObject_HEAD; 129 | } AtTime; 130 | 131 | // ctor 132 | static PyObject* 133 | AtTime_new( PyTypeObject* type, PyObject* args, PyObject* kwds ) { 134 | return (PyObject*)type->tp_alloc(type, 0); 135 | } 136 | 137 | static PyObject * AtTime_call( AtTime* self, PyObject* args, PyObject* kwds ); 138 | 139 | static int 140 | AtTime_init(AtTime *self, PyObject *args, PyObject *kwds) 141 | { 142 | Py_ssize_t argCount = PyTuple_Check(args) ? PyTuple_Size(args) : 0; 143 | if( argCount > 1 ) 144 | return -1; 145 | if( argCount == 1 ) { 146 | PyObject * result = AtTime_call( self, args, kwds ); 147 | Py_XDECREF(result); 148 | return result ? 0 : -1; 149 | } 150 | return 0; 151 | } 152 | 153 | // dtor 154 | static void 155 | AtTime_dealloc( PyObject* self ) { 156 | AtTime * at = (AtTime*)self; 157 | 158 | PyObject * tsd = PyThreadState_GetDict(); 159 | PyObject * atd = PyDict_GetItemString(tsd, "_AtTime" ); 160 | if( atd ) { 161 | PyObject * cur_stack = PyDict_GetItemString( atd, "current_stack" ); 162 | PyObject * time_stack = PyDict_GetItemString( atd, "time_stack" ); 163 | 164 | Py_ssize_t time_top = PyList_Size(time_stack) - 1; 165 | PyObject * hashKey = PyLong_FromLong( PyObject_Hash((PyObject*)self) ); 166 | Py_ssize_t pos = PySequence_Index(cur_stack, hashKey); 167 | Py_DECREF(hashKey); 168 | 169 | // Restore the correct time value if we are current 170 | if( PyList_Size(cur_stack) == pos + 1 ) { 171 | thread_local(current_time) = PyLong_AsLong( PyList_GetItem( time_stack, time_top ) ); 172 | //PySys_WriteStdout( "Current AtTime object destroyed, restoring thread_local(current_time) to %i\n", thread_local(current_time) ); 173 | PySequence_DelItem(time_stack,time_top); 174 | } else 175 | // If we aren't current, then we delete the time at the position one above where we are in the current_stack 176 | PySequence_DelItem(time_stack,pos+1); 177 | 178 | PySequence_DelItem(cur_stack,pos); 179 | 180 | // If we are the last AtTime object local to this thread, then remove the _AtTime thread-local dict 181 | if( PyList_Size(cur_stack) == 0 ) { 182 | thread_local(use_time_context) = (PyDict_GetItemString( atd, "restore_use_time_context" ) == Py_True) ? TRUE : FALSE; 183 | //PySys_WriteStdout( "Last AtTime object destroyed, setting thread_local(use_time_context) to FALSE\n" ); 184 | PyDict_DelItemString(tsd, "_AtTime"); 185 | } 186 | } 187 | self->ob_type->tp_free(self); 188 | } 189 | 190 | static PyObject * AtTime_call( AtTime* self, PyObject* args, PyObject* kwds ) 191 | { 192 | if( !PyTuple_Check(args) || (PyTuple_Size(args) != 1) || (!PyNumber_Check(PyTuple_GetItem(args,0))) ) { 193 | PyErr_SetString( PyExc_AttributeError, "Calling AtTime instances require a single time(int) argument" ); 194 | return 0; 195 | } 196 | 197 | int timeValue = PyInt_AsLong(PyTuple_GetItem(args,0)); 198 | if( PyErr_Occurred() ) 199 | return 0; 200 | 201 | PyObject * tsd = PyThreadState_GetDict(); 202 | PyObject * atd = PyDict_GetItemString(tsd, "_AtTime" ); 203 | 204 | // New reference is either transfered to a list, or decremented below 205 | PyObject * hashKey = PyLong_FromLong( PyObject_Hash((PyObject*)self) ); 206 | 207 | if( !atd ) { 208 | 209 | // New ref 210 | atd = PyDict_New(); 211 | 212 | PyDict_SetItemString( tsd, "_AtTime", atd ); 213 | // tsd now has a ref to atd 214 | Py_DECREF(atd); 215 | 216 | // New refs 217 | PyObject * time_stack = PyList_New(1), * cur_stack = PyList_New(1); 218 | 219 | // PyList_SetItem steals a reference 220 | PyList_SetItem( time_stack, 0, PyLong_FromLong(thread_local(current_time)) ); 221 | // Give our hashKey reference to cur_stack 222 | PyList_SetItem( cur_stack, 0, hashKey ); 223 | 224 | // Dicts take their own reference, so we release ours after this 225 | PyDict_SetItemString( atd, "time_stack", time_stack ); 226 | PyDict_SetItemString( atd, "current_stack", cur_stack ); 227 | Py_DECREF(time_stack); 228 | Py_DECREF(cur_stack); 229 | 230 | PyObject * utl = PyBool_FromLong( thread_local(use_time_context) ); 231 | // takes it's own ref, so we release ours 232 | PyDict_SetItemString( atd, "restore_use_time_context", utl ); 233 | Py_DECREF(utl); 234 | 235 | thread_local(use_time_context) = TRUE; 236 | //PySys_WriteStdout( "First AtTime struct activated, setting thread_local(use_time_context) to TRUE\n" ); 237 | } else { 238 | // Borrowed refs 239 | PyObject * time_stack = PyDict_GetItemString( atd, "time_stack" ); 240 | PyObject * cur_stack = PyDict_GetItemString( atd, "current_stack" ); 241 | 242 | Py_ssize_t pos = PySequence_Index(cur_stack, hashKey); 243 | 244 | // If we are already current then there is nothing to do 245 | if( pos != PyList_Size(cur_stack) - 1 ) { 246 | // If we have restore entries, but aren't current, then delete our existing restore entries 247 | if( pos >= 0 ) { 248 | //PySys_WriteStdout( "Deleting current entries in time and cur stack\n" ); 249 | PySequence_DelItem( time_stack, pos + 1 ); 250 | PySequence_DelItem( cur_stack, pos ); 251 | } 252 | // And add the new restore entries 253 | //PySys_WriteStdout( "Appending new entries in time and cur stack\n" ); 254 | PyList_Append(time_stack, PyLong_FromLong(thread_local(current_time)) ); 255 | PyList_Append(cur_stack, hashKey ); 256 | } else { 257 | //PySys_WriteStdout( "Already current, doing nothing but setting current_time\n" ); 258 | Py_DECREF(hashKey); 259 | } 260 | } 261 | 262 | //PySys_WriteStdout( "thread_local(current_time) set to %i\n", timeValue ); 263 | thread_local(current_time) = timeValue * GetTicksPerFrame(); 264 | 265 | Py_INCREF(Py_None); 266 | return Py_None; 267 | } 268 | 269 | static PyTypeObject AtTimeType = { 270 | PyObject_HEAD_INIT(NULL) 271 | 0, // ob_size 272 | "Py3dsMax.AtTime", // tp_name 273 | sizeof(AtTime), // tp_basicsize 274 | 0, // tp_itemsize 275 | (destructor)AtTime_dealloc, // tp_dealloc 276 | 0, // tp_print 277 | 0, // tp_getattr 278 | 0, // tp_setattr 279 | 0, // tp_compare 280 | 0, // tp_repr 281 | 0, // tp_as_number 282 | 0, // tp_as_sequence 283 | 0, // tp_as_mapping 284 | 0, // tp_hash 285 | (ternaryfunc)AtTime_call, // tp_call 286 | 0, // tp_str 287 | 0, // tp_getattro 288 | 0, // tp_setattro 289 | 0, // tp_as_buffer 290 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_CLASS, // tp_flags 291 | "MAXScript at time emulator", // tp_doc 292 | 0, // tp_traverse 293 | 0, // tp_clear 294 | 0, // tp_richcompare 295 | 0, // tp_weaklistoffset 296 | 0, // tp_iter 297 | 0, // tp_iternext 298 | 0, // tp_methods 299 | 0, // tp_members 300 | 0, // tp_getset 301 | 0, // tp_base 302 | 0, // tp_dict 303 | 0, // tp_descr_get 304 | 0, // tp_descr_set 305 | 0, // tp_dictoffset 306 | (initproc)AtTime_init, // tp_init 307 | 0, // tp_alloc 308 | AtTime_new, // tp_new 309 | }; 310 | 311 | //----------------------------------------------------------- 312 | // define the studio max module (Py3dsMax) 313 | 314 | // Py3dsMax.GetWindowHandle() - required for Qt/Ui parenting 315 | static PyObject* 316 | studiomax_getwindowhandle( PyObject* self ) { 317 | return PyInt_FromLong( (long)GetCOREInterface()->GetMAXHWnd() ); 318 | } 319 | 320 | // Py3dsMax.GetPluginInstance() - required for Qt/plugin parenting 321 | static PyObject* 322 | studiomax_getplugininstance( PyObject* self ) { 323 | return PyInt_FromLong( (long)ObjectWrapper::hInstance ); 324 | } 325 | 326 | // Py3dsMax.DispatchMessage() - passes along a message to the window 327 | static PyObject* 328 | studiomax_dispatchmessage( PyObject* self, PyObject* args ) { 329 | if ( args && PyTuple_Size(args) == 3 ) { 330 | MSG msg; 331 | msg.message = PyInt_AsLong( PyTuple_GetItem( args, 0 ) ); 332 | msg.wParam = PyInt_AsLong( PyTuple_GetItem( args, 1 ) ); 333 | msg.lParam = PyInt_AsLong( PyTuple_GetItem( args, 2 ) ); 334 | 335 | GetCOREInterface()->TranslateAndDispatchMAXMessage( msg ); 336 | 337 | Py_INCREF( Py_None ); 338 | return Py_None; 339 | } 340 | else { 341 | PyErr_SetString( PyExc_AttributeError, "Py3dsMax.DispatchMessage expects exactly 3 arguemnts" ); 342 | return NULL; 343 | } 344 | } 345 | 346 | // Py3dsMax.redo() - redoes the last action 347 | static PyObject* 348 | studiomax_redo( PyObject* self ) { 349 | ExecuteMAXScriptScript( _T("max redo") ); 350 | 351 | Py_INCREF( Py_True ); 352 | return Py_True; 353 | } 354 | 355 | // Py3dsMax.runScript() - runs a script file 356 | static PyObject* 357 | studiomax_runScript( PyObject* self, PyObject* args ) { 358 | char* filename = NULL; 359 | 360 | mprintf( _T("mxs_runScript entered") ); 361 | 362 | // Step 1: convert the input parameters 363 | if ( !PyArg_ParseTuple( args, "s", &filename ) ) { 364 | PyErr_SetString( PyExc_AttributeError, "Py3dsMax.runScript() is expecting a string input" ); 365 | return NULL; 366 | } 367 | 368 | // Step 2: load the file 369 | PyObject* py_file = PyFile_FromString( filename, "r" ); 370 | if ( !py_file ) { 371 | PyErr_SetString( PyExc_AttributeError, "Py3dsMax.runScript() got an invalid file input" ); 372 | return NULL; 373 | } 374 | 375 | // Step 3: run the file 376 | PyRun_SimpleFile( PyFile_AsFile(py_file), filename ); 377 | 378 | // Step 4: clear the memory 379 | Py_XDECREF( py_file ); 380 | 381 | if( PyErr_Occurred() ) 382 | return 0; 383 | 384 | // return true 385 | Py_INCREF( Py_True ); 386 | return Py_True; 387 | } 388 | 389 | static PyObject * 390 | studiomax_mprint( PyObject * self, PyObject * arg ) 391 | { 392 | PyStringToMCHAR mchar(arg); 393 | mprintf(mchar.mchar()); 394 | Py_INCREF(Py_None); 395 | return Py_None; 396 | } 397 | 398 | // Py3dsMax.undo() - undoes the last action 399 | static PyObject* 400 | studiomax_undo( PyObject* self ) { 401 | ExecuteMAXScriptScript( _T("max undo") ); 402 | 403 | Py_INCREF( Py_True ); 404 | return Py_True; 405 | } 406 | 407 | // Py3dsMax.undoOn() - set the undo system to be on 408 | static PyObject* 409 | studiomax_undoOn( PyObject* self ) { 410 | theHold.Begin(); 411 | 412 | Py_INCREF( Py_True ); 413 | return Py_True; 414 | } 415 | 416 | // Py3dsMax.undoOff() - set the undo system to be off 417 | static PyObject* 418 | studiomax_undoOff( PyObject* self, PyObject* args ) { 419 | MCHAR* name; 420 | 421 | #ifdef UNICODE 422 | const char * format = "u"; 423 | #else 424 | const char * format = "s"; 425 | #endif 426 | 427 | if ( !PyArg_ParseTuple( args, format, &name ) ) 428 | return NULL; 429 | 430 | theHold.Accept( name ); 431 | 432 | Py_INCREF( Py_True ); 433 | return Py_True; 434 | } 435 | 436 | /* 437 | 438 | static bool file_in( CharStream* source, CharStream* log ) { 439 | init_thread_locals(); 440 | push_alloc_frame(); 441 | three_typed_value_locals(Parser* parser, Value* code, Value* result); 442 | save_current_frames(); 443 | 444 | // these variables have been deprecated for maxscript in max 2012 445 | #ifdef __MAXSCRIPT_2012__ 446 | set_error_trace_back_disabled(FALSE); 447 | set_error_trace_back_active(TRUE); 448 | set_error_trace_back_level(10); 449 | #else 450 | disable_trace_back = FALSE; 451 | trace_back_active = TRUE; 452 | trace_back_levels = 10; 453 | #endif 454 | 455 | CharStream* out = thread_local(current_stdout); 456 | 457 | // loop through stream compiling & evaluating all expressions 458 | try { 459 | // make a new compiler instance 460 | vl.parser = new Parser(out); 461 | source->flush_whitespace(); 462 | while (!source->at_eos() || vl.parser->back_tracked) { 463 | // In max 2012 this line will error out when the line return is only \n (a linux convention) see http://redmine.blur.com/issues/6446 for more details. 464 | vl.code = vl.parser->compile(source); 465 | vl.result = vl.code->eval(); 466 | source->flush_whitespace(); 467 | } 468 | if ( vl.parser->expr_level != 0 || vl.parser->back_tracked && vl.parser->token != t_end ) 469 | throw; 470 | 471 | source->close(); 472 | } 473 | catch (...) { 474 | // catch any errors and tell what file we are in if any 475 | out->puts("Unknown MAXScript Error occurred Occurred: "); 476 | source->sprin1(out); 477 | source->close(); 478 | out->puts( "\n" ); 479 | pop_alloc_frame(); 480 | pop_value_locals(); 481 | return false; 482 | } 483 | 484 | pop_alloc_frame(); 485 | pop_value_locals(); 486 | return true; 487 | } 488 | 489 | // Py3dsMax.runMaxscript 490 | static PyObject* 491 | studiomax_runMaxscript( PyObject* self, PyObject* args ) { 492 | char* fname; 493 | 494 | if ( !PyArg_ParseTuple( args, "s", &fname ) ) 495 | return NULL; 496 | #if 1 497 | one_typed_value_local(FileStream * file); 498 | 499 | // open a fileStream instance on the file 500 | vl.file = (new FileStream)->open( fname, "rt"); 501 | if (vl.file == (FileStream*)&undefined) { 502 | PyErr_SetString( PyExc_RuntimeError, (TSTR("Py3dsMax.runMaxscript(filename): cannot open file - ") + fname) ); 503 | pop_value_locals(); 504 | return NULL; 505 | } 506 | 507 | bool result = 0; 508 | ExecuteScript(vl.file,&result); 509 | 510 | PyObject * out = result ? Py_True : Py_False; 511 | Py_INCREF(out); 512 | #else 513 | // pick up arguments 514 | two_typed_value_locals(FileStream* file, StringStream* log ); 515 | 516 | vl.log = new StringStream(); 517 | 518 | // open a fileStream instance on the file 519 | vl.file = (new FileStream)->open( fname, "rt"); 520 | if (vl.file == (FileStream*)&undefined) { 521 | PyErr_SetString( PyExc_RuntimeError, (TSTR("Py3dsMax.runMaxscript(filename): cannot open file - ") + fname) ); 522 | pop_value_locals(); 523 | return NULL; 524 | } 525 | 526 | // run using the stream-based filein utility 527 | PyObject* out = NULL; 528 | if ( !file_in( vl.file, vl.log ) ) { 529 | PyErr_SetString( PyExc_RuntimeError, vl.log->to_string() ); 530 | } 531 | else { 532 | Py_INCREF(Py_True); 533 | out = Py_True; 534 | } 535 | #endif 536 | 537 | pop_value_locals(); 538 | return out; 539 | } 540 | 541 | */ 542 | 543 | // Py3dsMax.getVisController() - get the visibility controller of a node 544 | static PyObject* 545 | studiomax_getVisController( PyObject* self, PyObject* args ) { 546 | PyObject * ret = 0; 547 | if ( PyTuple_Size(args) == 1 ) { 548 | // convert the input item to a maxscript value 549 | PyObject* item = PyTuple_GetItem(args,0); 550 | MXS_PROTECT(one_value_local(obj)); 551 | vl.obj = ObjectWrapper::intern(item); 552 | 553 | if ( is_node(vl.obj) ) { 554 | ret = ObjectWrapper::py_intern( MAXControl::intern( ((MAXNode*)vl.obj)->node->GetVisController() ) ); 555 | } 556 | MXS_CLEANUP(); 557 | } else { 558 | PyErr_SetString( PyExc_AttributeError, "getVisController takes one argument, a max object." ); 559 | return 0; 560 | } 561 | 562 | if( !ret ) { 563 | Py_INCREF( Py_None ); 564 | ret = Py_None; 565 | } 566 | return ret; 567 | } 568 | 569 | // Py3dsMax.setVisController() - set the visibility controller of a node 570 | static PyObject* 571 | studiomax_setVisController( PyObject* self, PyObject* args ) { 572 | bool success = false; 573 | if ( PyTuple_Size(args) == 2 ) { 574 | // convert the input items to maxscript values 575 | PyObject* item = PyTuple_GetItem(args,0); 576 | PyObject* pctl = PyTuple_GetItem(args,1); 577 | 578 | Value* obj = ObjectWrapper::intern(item); 579 | Value* ctrl = ObjectWrapper::intern(pctl); 580 | 581 | if ( is_node(obj) && is_controller(ctrl) ) { 582 | try { 583 | ((MAXNode*) obj)->node->SetVisController(((MAXControl*) ctrl)->controller); 584 | success = true; 585 | } 586 | catch ( ... ) {}; 587 | } 588 | } else { 589 | PyErr_SetString( PyExc_AttributeError, "setVisController takes two arguments, a max object and a visibility controller." ); 590 | return 0; 591 | } 592 | if ( success ) { 593 | Py_INCREF( Py_True ); 594 | return Py_True; 595 | } 596 | else { 597 | Py_INCREF( Py_False ); 598 | return Py_False; 599 | } 600 | } 601 | 602 | // Py3dsMax.getVersion() - gets the version number of Py3dsMax as a string 603 | static PyObject* 604 | studiomax_getVersion( PyObject* self ){ 605 | PyObject* vstr = PyString_FromString(BLURPYTHON_VERSION_STR); 606 | return vstr; 607 | } 608 | 609 | // define the Py3dsMax module built-in methods 610 | static PyMethodDef module_methods[] = { 611 | // windows methods 612 | { "GetWindowHandle", (PyCFunction)studiomax_getwindowhandle, METH_NOARGS, "Get the HWND value of the max window." }, 613 | { "GetPluginInstance", (PyCFunction)studiomax_getplugininstance, METH_NOARGS, "Get the HINSTANCE value of the max window." }, 614 | { "DispatchMessage", (PyCFunction)studiomax_dispatchmessage, METH_VARARGS, "Send the MAX Window a message." }, 615 | 616 | // maxscript undo stack 617 | { "redo", (PyCFunction)studiomax_redo, METH_NOARGS, "Redo's the lastest stack." }, 618 | { "undo", (PyCFunction)studiomax_undo, METH_NOARGS, "Undo's the latest stack." }, 619 | { "undoOn", (PyCFunction)studiomax_undoOn, METH_NOARGS, "Starts a new undo stack." }, 620 | { "undoOff", (PyCFunction)studiomax_undoOff, METH_VARARGS, "Finishes the current undo stack." }, 621 | 622 | // maxscript workarounds 623 | { "getVisController", (PyCFunction)studiomax_getVisController, METH_VARARGS, "Get a nodes visibility controller" }, 624 | { "setVisController", (PyCFunction)studiomax_setVisController, METH_VARARGS, "Set a nodes visibility controller" }, 625 | 626 | // python methods 627 | // { "runMaxscript", (PyCFunction)studiomax_runMaxscript, METH_VARARGS, "Runs a maxscript file for proper error checking" }, 628 | { "runScript", (PyCFunction)studiomax_runScript, METH_VARARGS, "Runs a python file in our global scope." }, 629 | { "mprint", (PyCFunction)studiomax_mprint, METH_O, "Prints a string to 3dsMax's listener." }, 630 | 631 | // Version Functions 632 | { "getVersion", (PyCFunction)studiomax_getVersion, METH_NOARGS, "Get the Py3dsMax version" }, 633 | 634 | { NULL, NULL, 0, NULL } 635 | }; 636 | 637 | // initialize the plugin 638 | PyMODINIT_FUNC 639 | init_module(void) { 640 | 641 | #ifndef __MAXSCRIPT_2015__ 642 | // Step 1: initialize python 643 | if (!Py_IsInitialized()) 644 | Py_Initialize(); 645 | #endif 646 | 647 | PyGILState_STATE gstate; 648 | gstate = PyGILState_Ensure(); 649 | 650 | // Step 2: make sure the mxs type is running 651 | if ( PyType_Ready(&MxsType) < 0 ) { 652 | return; 653 | } 654 | 655 | if ( PyType_Ready(&ValueWrapperType) < 0 ) { 656 | return; 657 | } 658 | 659 | if ( PyType_Ready(&AtTimeType) < 0 ) { 660 | return; 661 | } 662 | 663 | TypedFloatType_init(); 664 | 665 | // Step 3: make sure the object wrapper is running 666 | if ( !ObjectWrapper::init() ) { 667 | return; 668 | } 669 | 670 | // Step 4: initialize the Py3dsMax module 671 | PyObject* module = Py_InitModule3( "Py3dsMax", module_methods, "Python interface into 3d Studio Max" ); 672 | 673 | if ( !module ) { 674 | return; 675 | } 676 | 677 | // Step 4: create the mxs class in the Py3dsMax module 678 | PyObject* instance = mxs_new( &MxsType, NULL, NULL ); 679 | PyModule_AddObject( module, "mxs", instance ); 680 | 681 | Py_INCREF(&ValueWrapperType); 682 | PyModule_AddObject( module, "ValueWrapper", (PyObject*)&ValueWrapperType ); 683 | 684 | Py_INCREF(&AtTimeType); 685 | PyModule_AddObject( module, "AtTime", (PyObject*)&AtTimeType ); 686 | 687 | PyGILState_Release(gstate); 688 | 689 | Py_INCREF(&TypedFloatType); 690 | PyModule_AddObject( module, "TypedFloat", (PyObject*)&TypedFloatType ); 691 | 692 | mprintf( _T("[blurPython] DLL has been successfully loaded.\n") ); 693 | } 694 | -------------------------------------------------------------------------------- /version_h_template.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Versioning is handled through a couple of files and a pre-build event 3 | to allow svn revision numbers to automatically be included/incremented. 4 | 5 | version.h: this is an auto-generated file with the build date and svn 6 | revision number of the project.It is included throughout the project 7 | to get the version and build info it defines. 8 | 9 | version_h_template.txt: Template used when building version.h 10 | 11 | buildVersion.py: Uses "git describe --long" to generate the major, minor, 12 | patch, and revision values used by version_h_template.txt and generates 13 | the version.h file used when compiling. This is called in a pre-build 14 | event. 15 | 16 | Git tags: Git tags should always follow this format. v[major].[minor].[patch] 17 | replacing the contents of each [] with a version number. 18 | 19 | */ 20 | 21 | #define BLURPYTHON_VERSION_MAJOR {major} 22 | #define BLURPYTHON_VERSION_MINOR {minor} 23 | #define BLURPYTHON_VERSION_PATCH {patch} 24 | #define BLURPYTHON_VERSION_REV {revCount} 25 | #define BLURPYTHON_VERSION_STR "{major},{minor},{patch},{revCount}-{rev}" 26 | #define BLURPYTHON_BUILDDATE "{datetime}" 27 | 28 | 29 | -------------------------------------------------------------------------------- /wrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | \file wrapper.h 3 | 4 | \remarks This is the main class definition for the wrapper classes. 5 | * ValueWrapper is a PyObject* class that wraps a Value* class 6 | * ObjectWrapper is a Value* class that wraps a PyObject* class 7 | 8 | \author Blur Studio (c) 2010 9 | \email beta@blur.com 10 | 11 | \license This software is released under the GNU General Public License. For more info, visit: http://www.gnu.org/ 12 | */ 13 | 14 | #ifndef __WRAPPER_H__ 15 | #define __WRAPPER_H__ 16 | 17 | #include "imports.h" 18 | 19 | visible_class( ObjectWrapper ); 20 | class ObjectWrapper : public Value { 21 | private: 22 | PyObject* mObject; 23 | PyObject* mObjectDict; 24 | PyObject* mPyString; 25 | public: 26 | ObjectWrapper( PyObject* obj = NULL ); 27 | ~ObjectWrapper(); 28 | 29 | // maxscript value methods 30 | __declspec( dllexport ) virtual Value* eq_vf( Value** arg_list, int arg_count ); 31 | __declspec( dllexport ) virtual Value* get_vf( Value** arg_list, int arg_count ); 32 | __declspec( dllexport ) virtual Value* put_vf( Value** arg_list, int arg_count ); 33 | 34 | // maxscript value comparisons 35 | classof_methods( ObjectWrapper, Value ); 36 | #define is_objectwrapper(o) ((o)->tag == class_tag(ObjectWrapper)) 37 | #define is_maxmodifierarray(o) ((o)->tag == class_tag(MAXModifierArray)) 38 | 39 | // objectwrapper instance methods 40 | Value* apply( Value** arg_list, int count, CallContext* cc = 0 ); 41 | virtual void collect(); 42 | Value* get_property( Value** arg_list, int count ); 43 | Value* set_property( Value** arg_list, int count ); 44 | PyObject* object(); 45 | void sprin1( CharStream* s ); 46 | const MCHAR* to_string(); 47 | 48 | BOOL _is_collection() { return 1; } 49 | BOOL _is_function() { return 1; } 50 | 51 | // objectwrapper static methods 52 | static Value* intern( PyObject* obj, bool unwrap = true ); 53 | static Value* collectionMapper( Value** args, int count ); 54 | static bool init(); 55 | static void handleMaxscriptError(); 56 | static bool is_wrapper( PyObject* obj ); 57 | static void log( PyObject* obj ); 58 | static PyObject* py_intern( Value* val ); 59 | 60 | static HMODULE hInstance; 61 | }; 62 | 63 | struct ValueWrapper { 64 | PyObject_HEAD 65 | Value* mValue; // Pointer to the MAXScript Value 66 | // Double linked list of ValueWrappers, used to provide 67 | // O(n) iteration by the Protector class, and O(1) insertion 68 | // and deletion. The Protector stores the head of the list. 69 | ValueWrapper * mPrev, * mNext; 70 | PyObject* dict; 71 | }; 72 | 73 | // Define the type object struct for use externally when building the 74 | // Py3dsMax module, so that we have access to the type from the module. 75 | extern PyTypeObject ValueWrapperType; 76 | extern PyTypeObject TypedFloatType; 77 | void TypedFloatType_init(); 78 | 79 | 80 | // Converts a python string object to MCHAR * 81 | class PyStringToMCHAR { 82 | public: 83 | PyStringToMCHAR( PyObject *, bool stealRef=false ); 84 | PyStringToMCHAR( const char * ); 85 | ~PyStringToMCHAR(); 86 | const MCHAR * mchar(); 87 | protected: 88 | PyObject * mObject; 89 | #ifndef UNICODE 90 | const char * mData; 91 | #endif 92 | }; 93 | 94 | // Converts am MCHAR * to a python string 95 | class MCharToPyString { 96 | public: 97 | MCharToPyString( const MCHAR * ); 98 | ~MCharToPyString(); 99 | // Returns borrowed ref 100 | PyObject * pyString(); 101 | // Returns a new ref 102 | PyObject * pyStringRef(); 103 | // Returns the internal data of the python string, same as PyString_AsString(pyString()); 104 | const char * data(); 105 | protected: 106 | const MCHAR * mMChars; 107 | PyObject * mObject; 108 | #ifdef UNICODE 109 | PyObject * mUtf8Object; 110 | #endif 111 | }; 112 | 113 | #endif __WRAPPER_H__ 114 | --------------------------------------------------------------------------------