├── .gitignore ├── DDConvexHull.sln ├── DDConvexHull.vcxproj ├── DDConvexHull.vcxproj.filters ├── DDConvexHull.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── DDConvexHullCmd.cpp ├── DDConvexHullCmd.h ├── DDConvexHullNode.cpp ├── DDConvexHullNode.h ├── DDConvexHullPlugin.cpp ├── DDConvexHullUtils.cpp ├── DDConvexHullUtils.h ├── LICENSE.txt ├── Models ├── stanfordbunny.mb └── stanfordbunny.obj ├── README.md ├── Scripts ├── AETemplates │ └── AEDDConvexHullTemplate.mel └── DDConvexHullUtils.py └── StanHull ├── hull.cpp ├── hull.h ├── readme.txt ├── stanhull.cpp ├── wavefront.cpp └── wavefront.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio files that shouldn't be submitted 2 | *.suo 3 | *.sdf 4 | *.proj.user 5 | *.vcxproj.user 6 | *.pdb 7 | *.ilk 8 | *.lastbuildstate 9 | *.exp 10 | *.tlog 11 | *.intermediate.manifest 12 | *.log 13 | *.ipch 14 | 15 | *.cache 16 | *.idb 17 | *.opensdf 18 | 19 | # Ignore for this project as its a DLL, not a static lib 20 | *.lib 21 | 22 | # Whitelist .obj model files 23 | *.obj 24 | !Models/*.obj 25 | 26 | 27 | # Python .pyc and .pyo 28 | *.pyc 29 | *.pyo 30 | 31 | ##### 32 | # OS X temporary files that should never be committed 33 | 34 | .DS_Store 35 | *.swp 36 | *.lock 37 | profile 38 | 39 | 40 | #### 41 | # Xcode temporary files that should never be committed 42 | # 43 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this... 44 | *~.nib 45 | 46 | 47 | #### 48 | # Xcode build files - 49 | # 50 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData" 51 | DerivedData/ 52 | 53 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build" 54 | build/ 55 | 56 | 57 | ##### 58 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) 59 | # 60 | # This is complicated: 61 | # 62 | # SOMETIMES you need to put this file in version control. 63 | # Apple designed it poorly - if you use "custom executables", they are 64 | # saved in this file. 65 | # 99% of projects do NOT use those, so they do NOT want to version control this file. 66 | # ..but if you're in the 1%, comment out the line "*.pbxuser" 67 | *.pbxuser 68 | *.mode1v3 69 | *.mode2v3 70 | *.perspectivev3 71 | # NB: also, whitelist the default ones, some projects need to use these 72 | !default.pbxuser 73 | !default.mode1v3 74 | !default.mode2v3 75 | !default.perspectivev3 76 | 77 | 78 | #### 79 | # Xcode 4 - semi-personal settings, often included in workspaces 80 | # 81 | # You can safely ignore the xcuserdata files - but do NOT ignore the files next to them 82 | # 83 | 84 | xcuserdata 85 | 86 | #### 87 | # XCode 4 workspaces - more detailed 88 | # 89 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :) 90 | !xcshareddata 91 | 92 | #### 93 | # XCode 4 build-schemes 94 | # 95 | # PRIVATE ones are stored inside xcuserdata 96 | !xcschemes 97 | 98 | #### 99 | # Xcode 4 - Deprecated classes 100 | # 101 | # Allegedly, if you manually "deprecate" your classes, they get moved here. 102 | # 103 | # We're using source-control, so this is a "feature" that we do not want! 104 | 105 | *.moved-aside 106 | -------------------------------------------------------------------------------- /DDConvexHull.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DDConvexHull", "DDConvexHull.vcxproj", "{CACBE6A2-1649-4A82-B1A0-997F8BEADA77}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Debug|Win32.Build.0 = Debug|Win32 16 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Debug|x64.ActiveCfg = Debug|x64 17 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Debug|x64.Build.0 = Debug|x64 18 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Release|Win32.ActiveCfg = Release|Win32 19 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Release|Win32.Build.0 = Release|Win32 20 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Release|x64.ActiveCfg = Release|x64 21 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /DDConvexHull.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {CACBE6A2-1649-4A82-B1A0-997F8BEADA77} 23 | DDConvexHull 24 | 25 | 26 | 27 | DynamicLibrary 28 | true 29 | MultiByte 30 | 31 | 32 | DynamicLibrary 33 | true 34 | MultiByte 35 | 36 | 37 | DynamicLibrary 38 | false 39 | true 40 | MultiByte 41 | 42 | 43 | DynamicLibrary 44 | false 45 | true 46 | MultiByte 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | .mll 66 | $(SolutionDir)$(Platform)\$(Configuration)\ 67 | $(Platform)\$(Configuration)\ 68 | 69 | 70 | .mll 71 | $(SolutionDir)$(Platform)\$(Configuration)\ 72 | $(Platform)\$(Configuration)\ 73 | 74 | 75 | .mll 76 | $(SolutionDir)$(Platform)\$(Configuration)\ 77 | $(Platform)\$(Configuration)\ 78 | 79 | 80 | .mll 81 | $(SolutionDir)$(Platform)\$(Configuration)\ 82 | $(Platform)\$(Configuration)\ 83 | 84 | 85 | 86 | Level3 87 | Disabled 88 | REQUIRE_IOSTREAM;NT_PLUGIN;%(PreprocessorDefinitions) 89 | C:\Program Files %28x86%29\Autodesk\Maya2013\include;%(AdditionalIncludeDirectories) 90 | 91 | 92 | true 93 | Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) 94 | C:\Program Files %28x86%29\Autodesk\Maya2013\lib;%(AdditionalLibraryDirectories) 95 | /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) 96 | 97 | 98 | 99 | 100 | Level3 101 | Disabled 102 | C:\Program Files\Autodesk\Maya2013\include;%(AdditionalIncludeDirectories) 103 | REQUIRE_IOSTREAM;NT_PLUGIN;%(PreprocessorDefinitions) 104 | 105 | 106 | true 107 | C:\Program Files\Autodesk\Maya2013\lib;%(AdditionalLibraryDirectories) 108 | Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) 109 | /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) 110 | 111 | 112 | 113 | 114 | Level3 115 | Full 116 | true 117 | true 118 | REQUIRE_IOSTREAM;NT_PLUGIN;%(PreprocessorDefinitions) 119 | C:\Program Files %28x86%29\Autodesk\Maya2013\include;%(AdditionalIncludeDirectories) 120 | 121 | 122 | false 123 | true 124 | true 125 | Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) 126 | C:\Program Files %28x86%29\Autodesk\Maya2013\lib;%(AdditionalLibraryDirectories) 127 | /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) 128 | 129 | 130 | 131 | 132 | Level3 133 | Full 134 | true 135 | true 136 | C:\Program Files\Autodesk\Maya2013\include;%(AdditionalIncludeDirectories) 137 | REQUIRE_IOSTREAM;NT_PLUGIN;%(PreprocessorDefinitions) 138 | 139 | 140 | false 141 | true 142 | true 143 | C:\Program Files\Autodesk\Maya2013\lib;%(AdditionalLibraryDirectories) 144 | Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) 145 | /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /DDConvexHull.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {ab93e8f8-e9a7-47d7-a866-7320f2874f1e} 18 | 19 | 20 | {85537370-e064-4b9b-a1b9-dd1940c24be2} 21 | 22 | 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files\StanHull 35 | 36 | 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files\StanHull 52 | 53 | 54 | -------------------------------------------------------------------------------- /DDConvexHull.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6D0D36BC1690CBCE0007D530 /* DDConvexHullNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0D36BA1690CBCE0007D530 /* DDConvexHullNode.cpp */; }; 11 | 6D0D36BD1690CBCE0007D530 /* DDConvexHullNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D0D36BB1690CBCE0007D530 /* DDConvexHullNode.h */; }; 12 | 6D0D36C21690D1F70007D530 /* DDConvexHullPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0D36C11690D1F70007D530 /* DDConvexHullPlugin.cpp */; }; 13 | 6D0D36C71690DDF90007D530 /* hull.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0D36C41690DDF90007D530 /* hull.cpp */; }; 14 | 6D0D36C81690DDF90007D530 /* hull.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D0D36C51690DDF90007D530 /* hull.h */; }; 15 | 6D26E39316B792E2007148BB /* DDConvexHullUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D26E39116B792E2007148BB /* DDConvexHullUtils.cpp */; }; 16 | 6D26E39416B792E2007148BB /* DDConvexHullUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D26E39216B792E2007148BB /* DDConvexHullUtils.h */; }; 17 | 6DECFAE81693557F0009A010 /* stanhull.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DECFAD6169354990009A010 /* stanhull.cpp */; }; 18 | 6DECFAE91693557F0009A010 /* wavefront.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DECFAD7169354990009A010 /* wavefront.cpp */; }; 19 | 6DECFAEB1693557F0009A010 /* hull.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0D36C41690DDF90007D530 /* hull.cpp */; }; 20 | 6DECFAF31693AFA60009A010 /* DDConvexHullCmd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6DECFAF11693AFA60009A010 /* DDConvexHullCmd.cpp */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXCopyFilesBuildPhase section */ 24 | 6DECFADC169354C00009A010 /* CopyFiles */ = { 25 | isa = PBXCopyFilesBuildPhase; 26 | buildActionMask = 2147483647; 27 | dstPath = /usr/share/man/man1/; 28 | dstSubfolderSpec = 0; 29 | files = ( 30 | ); 31 | runOnlyForDeploymentPostprocessing = 1; 32 | }; 33 | /* End PBXCopyFilesBuildPhase section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 6D0D36AF1690C86D0007D530 /* DDConvexHull.bundle */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = DDConvexHull.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 6D0D36BA1690CBCE0007D530 /* DDConvexHullNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DDConvexHullNode.cpp; sourceTree = ""; }; 38 | 6D0D36BB1690CBCE0007D530 /* DDConvexHullNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDConvexHullNode.h; sourceTree = ""; }; 39 | 6D0D36C11690D1F70007D530 /* DDConvexHullPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DDConvexHullPlugin.cpp; sourceTree = ""; }; 40 | 6D0D36C41690DDF90007D530 /* hull.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = hull.cpp; path = StanHull/hull.cpp; sourceTree = ""; }; 41 | 6D0D36C51690DDF90007D530 /* hull.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hull.h; path = StanHull/hull.h; sourceTree = ""; }; 42 | 6D0D36C61690DDF90007D530 /* readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = readme.txt; path = StanHull/readme.txt; sourceTree = ""; }; 43 | 6D26E39116B792E2007148BB /* DDConvexHullUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DDConvexHullUtils.cpp; sourceTree = ""; }; 44 | 6D26E39216B792E2007148BB /* DDConvexHullUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDConvexHullUtils.h; sourceTree = ""; }; 45 | 6D9337A716DB429300C46A64 /* AEDDConvexHullTemplate.mel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = AEDDConvexHullTemplate.mel; path = Scripts/AETemplates/AEDDConvexHullTemplate.mel; sourceTree = ""; }; 46 | 6DECFAD6169354990009A010 /* stanhull.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = stanhull.cpp; path = StanHull/stanhull.cpp; sourceTree = ""; }; 47 | 6DECFAD7169354990009A010 /* wavefront.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = wavefront.cpp; path = StanHull/wavefront.cpp; sourceTree = ""; }; 48 | 6DECFAD8169354990009A010 /* wavefront.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = wavefront.h; path = StanHull/wavefront.h; sourceTree = ""; }; 49 | 6DECFADE169354C00009A010 /* StanHull */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = StanHull; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 6DECFAF11693AFA60009A010 /* DDConvexHullCmd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DDConvexHullCmd.cpp; sourceTree = ""; }; 51 | 6DECFAF51693B08D0009A010 /* DDConvexHullCmd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DDConvexHullCmd.h; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 6D0D36AC1690C86D0007D530 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | 6DECFADB169354C00009A010 /* Frameworks */ = { 63 | isa = PBXFrameworksBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | 6D0D36A41690C86D0007D530 = { 73 | isa = PBXGroup; 74 | children = ( 75 | 6D0D36B91690CBB50007D530 /* Source */, 76 | 6D0D36B01690C86D0007D530 /* Products */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 6D0D36B01690C86D0007D530 /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 6D0D36AF1690C86D0007D530 /* DDConvexHull.bundle */, 84 | 6DECFADE169354C00009A010 /* StanHull */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | 6D0D36B91690CBB50007D530 /* Source */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 6DECFAED1693696E0009A010 /* Scripts */, 93 | 6D0D36C31690DDE30007D530 /* StanHull */, 94 | 6D0D36BA1690CBCE0007D530 /* DDConvexHullNode.cpp */, 95 | 6D0D36BB1690CBCE0007D530 /* DDConvexHullNode.h */, 96 | 6D0D36C11690D1F70007D530 /* DDConvexHullPlugin.cpp */, 97 | 6DECFAF11693AFA60009A010 /* DDConvexHullCmd.cpp */, 98 | 6DECFAF51693B08D0009A010 /* DDConvexHullCmd.h */, 99 | 6D26E39116B792E2007148BB /* DDConvexHullUtils.cpp */, 100 | 6D26E39216B792E2007148BB /* DDConvexHullUtils.h */, 101 | ); 102 | name = Source; 103 | sourceTree = ""; 104 | }; 105 | 6D0D36C31690DDE30007D530 /* StanHull */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 6DECFAD6169354990009A010 /* stanhull.cpp */, 109 | 6DECFAD7169354990009A010 /* wavefront.cpp */, 110 | 6DECFAD8169354990009A010 /* wavefront.h */, 111 | 6D0D36C41690DDF90007D530 /* hull.cpp */, 112 | 6D0D36C51690DDF90007D530 /* hull.h */, 113 | 6D0D36C61690DDF90007D530 /* readme.txt */, 114 | ); 115 | name = StanHull; 116 | sourceTree = ""; 117 | }; 118 | 6D9337A816DB429B00C46A64 /* AETemplates */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 6D9337A716DB429300C46A64 /* AEDDConvexHullTemplate.mel */, 122 | ); 123 | name = AETemplates; 124 | sourceTree = ""; 125 | }; 126 | 6DECFAED1693696E0009A010 /* Scripts */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 6D9337A816DB429B00C46A64 /* AETemplates */, 130 | ); 131 | name = Scripts; 132 | sourceTree = ""; 133 | }; 134 | /* End PBXGroup section */ 135 | 136 | /* Begin PBXHeadersBuildPhase section */ 137 | 6D0D36AD1690C86D0007D530 /* Headers */ = { 138 | isa = PBXHeadersBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | 6D0D36BD1690CBCE0007D530 /* DDConvexHullNode.h in Headers */, 142 | 6D0D36C81690DDF90007D530 /* hull.h in Headers */, 143 | 6D26E39416B792E2007148BB /* DDConvexHullUtils.h in Headers */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXHeadersBuildPhase section */ 148 | 149 | /* Begin PBXNativeTarget section */ 150 | 6D0D36AE1690C86D0007D530 /* DDConvexHull */ = { 151 | isa = PBXNativeTarget; 152 | buildConfigurationList = 6D0D36B31690C86D0007D530 /* Build configuration list for PBXNativeTarget "DDConvexHull" */; 153 | buildPhases = ( 154 | 6D0D36AB1690C86D0007D530 /* Sources */, 155 | 6D0D36AC1690C86D0007D530 /* Frameworks */, 156 | 6D0D36AD1690C86D0007D530 /* Headers */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = DDConvexHull; 163 | productName = DDConvexHull; 164 | productReference = 6D0D36AF1690C86D0007D530 /* DDConvexHull.bundle */; 165 | productType = "com.apple.product-type.library.dynamic"; 166 | }; 167 | 6DECFADD169354C00009A010 /* StanHull */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = 6DECFAE5169354C00009A010 /* Build configuration list for PBXNativeTarget "StanHull" */; 170 | buildPhases = ( 171 | 6DECFADA169354C00009A010 /* Sources */, 172 | 6DECFADB169354C00009A010 /* Frameworks */, 173 | 6DECFADC169354C00009A010 /* CopyFiles */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | ); 179 | name = StanHull; 180 | productName = StanHull; 181 | productReference = 6DECFADE169354C00009A010 /* StanHull */; 182 | productType = "com.apple.product-type.tool"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | 6D0D36A61690C86D0007D530 /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | LastUpgradeCheck = 0460; 191 | ORGANIZATIONNAME = "Jonathan Tilden"; 192 | }; 193 | buildConfigurationList = 6D0D36A91690C86D0007D530 /* Build configuration list for PBXProject "DDConvexHull" */; 194 | compatibilityVersion = "Xcode 3.2"; 195 | developmentRegion = English; 196 | hasScannedForEncodings = 0; 197 | knownRegions = ( 198 | en, 199 | ); 200 | mainGroup = 6D0D36A41690C86D0007D530; 201 | productRefGroup = 6D0D36B01690C86D0007D530 /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 6D0D36AE1690C86D0007D530 /* DDConvexHull */, 206 | 6DECFADD169354C00009A010 /* StanHull */, 207 | ); 208 | }; 209 | /* End PBXProject section */ 210 | 211 | /* Begin PBXSourcesBuildPhase section */ 212 | 6D0D36AB1690C86D0007D530 /* Sources */ = { 213 | isa = PBXSourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | 6D0D36BC1690CBCE0007D530 /* DDConvexHullNode.cpp in Sources */, 217 | 6D0D36C21690D1F70007D530 /* DDConvexHullPlugin.cpp in Sources */, 218 | 6D0D36C71690DDF90007D530 /* hull.cpp in Sources */, 219 | 6DECFAF31693AFA60009A010 /* DDConvexHullCmd.cpp in Sources */, 220 | 6D26E39316B792E2007148BB /* DDConvexHullUtils.cpp in Sources */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | 6DECFADA169354C00009A010 /* Sources */ = { 225 | isa = PBXSourcesBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | 6DECFAE81693557F0009A010 /* stanhull.cpp in Sources */, 229 | 6DECFAE91693557F0009A010 /* wavefront.cpp in Sources */, 230 | 6DECFAEB1693557F0009A010 /* hull.cpp in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin XCBuildConfiguration section */ 237 | 6D0D36B11690C86D0007D530 /* Debug */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ALWAYS_SEARCH_USER_PATHS = NO; 241 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 243 | CLANG_CXX_LIBRARY = "libc++"; 244 | CLANG_WARN_EMPTY_BODY = YES; 245 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 246 | COPY_PHASE_STRIP = NO; 247 | EXECUTABLE_EXTENSION = ""; 248 | EXECUTABLE_SUFFIX = ""; 249 | GCC_C_LANGUAGE_STANDARD = gnu99; 250 | GCC_DYNAMIC_NO_PIC = NO; 251 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 252 | GCC_OPTIMIZATION_LEVEL = 0; 253 | GCC_PREPROCESSOR_DEFINITIONS = ( 254 | "DEBUG=1", 255 | OSMac_, 256 | MAC_PLUGIN, 257 | _BOOL, 258 | REQUIRE_IOSTREAM, 259 | ); 260 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 261 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 262 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 263 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 264 | GCC_WARN_UNUSED_VARIABLE = YES; 265 | GENERATE_MASTER_OBJECT_FILE = YES; 266 | HEADER_SEARCH_PATHS = ( 267 | ., 268 | ./StanHull, 269 | /Applications/Autodesk/maya2013/devkit/include, 270 | ); 271 | MACH_O_TYPE = mh_bundle; 272 | MACOSX_DEPLOYMENT_TARGET = 10.8; 273 | ONLY_ACTIVE_ARCH = YES; 274 | OTHER_LDFLAGS = ""; 275 | SDKROOT = macosx; 276 | }; 277 | name = Debug; 278 | }; 279 | 6D0D36B21690C86D0007D530 /* Release */ = { 280 | isa = XCBuildConfiguration; 281 | buildSettings = { 282 | ALWAYS_SEARCH_USER_PATHS = NO; 283 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 284 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 285 | CLANG_CXX_LIBRARY = "libc++"; 286 | CLANG_WARN_EMPTY_BODY = YES; 287 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 288 | COPY_PHASE_STRIP = YES; 289 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 290 | EXECUTABLE_EXTENSION = ""; 291 | EXECUTABLE_SUFFIX = ""; 292 | GCC_C_LANGUAGE_STANDARD = gnu99; 293 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 294 | GCC_PREPROCESSOR_DEFINITIONS = ( 295 | OSMac_, 296 | MAC_PLUGIN, 297 | _BOOL, 298 | REQUIRE_IOSTREAM, 299 | ); 300 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 301 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 302 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 303 | GCC_WARN_UNUSED_VARIABLE = YES; 304 | GENERATE_MASTER_OBJECT_FILE = YES; 305 | HEADER_SEARCH_PATHS = ( 306 | ., 307 | ./StanHull, 308 | /Applications/Autodesk/maya2013/devkit/include, 309 | ); 310 | MACH_O_TYPE = mh_bundle; 311 | MACOSX_DEPLOYMENT_TARGET = 10.8; 312 | OTHER_LDFLAGS = ""; 313 | SDKROOT = macosx; 314 | }; 315 | name = Release; 316 | }; 317 | 6D0D36B41690C86D0007D530 /* Debug */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 321 | COMBINE_HIDPI_IMAGES = YES; 322 | DYLIB_COMPATIBILITY_VERSION = ""; 323 | DYLIB_CURRENT_VERSION = ""; 324 | EXECUTABLE_EXTENSION = bundle; 325 | EXECUTABLE_PREFIX = ""; 326 | EXECUTABLE_SUFFIX = .bundle; 327 | LIBRARY_SEARCH_PATHS = ( 328 | ., 329 | /Applications/Autodesk/maya2013/Maya.app/Contents/MacOS, 330 | ); 331 | OTHER_LDFLAGS = ( 332 | "-Wl,-executable_path,/Applications/Autodesk/maya2013/Maya.app/Contents/MacOS", 333 | "-Wl,-exported_symbol,__Z16initializePlugin7MObject", 334 | "-Wl,-exported_symbol,__Z18uninitializePlugin7MObject", 335 | "-lOpenMaya", 336 | "-lFoundation", 337 | ); 338 | PRODUCT_NAME = "$(TARGET_NAME)"; 339 | }; 340 | name = Debug; 341 | }; 342 | 6D0D36B51690C86D0007D530 /* Release */ = { 343 | isa = XCBuildConfiguration; 344 | buildSettings = { 345 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 346 | COMBINE_HIDPI_IMAGES = YES; 347 | DYLIB_COMPATIBILITY_VERSION = ""; 348 | DYLIB_CURRENT_VERSION = ""; 349 | EXECUTABLE_EXTENSION = bundle; 350 | EXECUTABLE_PREFIX = ""; 351 | EXECUTABLE_SUFFIX = .bundle; 352 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO; 353 | LIBRARY_SEARCH_PATHS = ( 354 | ., 355 | /Applications/Autodesk/maya2013/Maya.app/Contents/MacOS, 356 | ); 357 | OTHER_LDFLAGS = ( 358 | "-Wl,-executable_path,/Applications/Autodesk/maya2013/Maya.app/Contents/MacOS", 359 | "-Wl,-exported_symbol,__Z16initializePlugin7MObject", 360 | "-Wl,-exported_symbol,__Z18uninitializePlugin7MObject", 361 | "-lOpenMaya", 362 | "-lFoundation", 363 | ); 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | }; 366 | name = Release; 367 | }; 368 | 6DECFAE6169354C00009A010 /* Debug */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 372 | GCC_PREPROCESSOR_DEFINITIONS = ( 373 | "DEBUG=1", 374 | "$(inherited)", 375 | ); 376 | MACH_O_TYPE = mh_execute; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | }; 379 | name = Debug; 380 | }; 381 | 6DECFAE7169354C00009A010 /* Release */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 385 | MACH_O_TYPE = mh_execute; 386 | PRODUCT_NAME = "$(TARGET_NAME)"; 387 | }; 388 | name = Release; 389 | }; 390 | /* End XCBuildConfiguration section */ 391 | 392 | /* Begin XCConfigurationList section */ 393 | 6D0D36A91690C86D0007D530 /* Build configuration list for PBXProject "DDConvexHull" */ = { 394 | isa = XCConfigurationList; 395 | buildConfigurations = ( 396 | 6D0D36B11690C86D0007D530 /* Debug */, 397 | 6D0D36B21690C86D0007D530 /* Release */, 398 | ); 399 | defaultConfigurationIsVisible = 0; 400 | defaultConfigurationName = Release; 401 | }; 402 | 6D0D36B31690C86D0007D530 /* Build configuration list for PBXNativeTarget "DDConvexHull" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | 6D0D36B41690C86D0007D530 /* Debug */, 406 | 6D0D36B51690C86D0007D530 /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | 6DECFAE5169354C00009A010 /* Build configuration list for PBXNativeTarget "StanHull" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | 6DECFAE6169354C00009A010 /* Debug */, 415 | 6DECFAE7169354C00009A010 /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | /* End XCConfigurationList section */ 421 | }; 422 | rootObject = 6D0D36A61690C86D0007D530 /* Project object */; 423 | } 424 | -------------------------------------------------------------------------------- /DDConvexHull.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DDConvexHullCmd.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // DDConvexHullCmd.cpp 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 1/1/13. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | #include "DDConvexHullCmd.h" 30 | #include "DDConvexHullUtils.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | MString DDConvexHullCmd::dbl_to_string(double x) 40 | { 41 | std::ostringstream ss; 42 | ss << x; 43 | return MString((ss.str()).c_str()); 44 | } 45 | 46 | MString DDConvexHullCmd::int_to_string(int x) 47 | { 48 | std::ostringstream ss; 49 | ss << x; 50 | return MString((ss.str()).c_str()); 51 | } 52 | 53 | MStatus DDConvexHullCmd::doIt(const MArgList& args) 54 | { 55 | if (args.length() != 1) 56 | { 57 | MGlobal::displayError("Needs at least 2 args"); 58 | return MS::kFailure; 59 | } 60 | MString input = args.asString(0); 61 | MString output = args.asString(1); 62 | 63 | // Get the mObject for the input 64 | MSelectionList selList; 65 | selList.add(input); 66 | MDagPath inputMesh; 67 | selList.getDagPath(0, inputMesh); 68 | 69 | // Ensure we're looking at the shape 70 | inputMesh.extendToShape(); 71 | 72 | // Create output object 73 | MDagModifier dm; 74 | MObject outMeshNode = dm.createNode(MFn::kMesh); 75 | MFnDependencyNode outMeshDag(outMeshNode); 76 | outMeshDag.setName("poopShape#"); 77 | DDConvexHullUtils::hullOpts hullOptions; 78 | return DDConvexHullUtils::generateMayaHull(outMeshNode, 79 | inputMesh.node(), hullOptions); 80 | 81 | } 82 | 83 | void* DDConvexHullCmd::creator() 84 | { 85 | return new DDConvexHullCmd; 86 | } -------------------------------------------------------------------------------- /DDConvexHullCmd.h: -------------------------------------------------------------------------------- 1 | // 2 | // DDConvexHullCmd.h 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 1/1/13. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | #ifndef DDConvexHull_DDConvexHullCmd_h 30 | #define DDConvexHull_DDConvexHullCmd_h 31 | 32 | #include 33 | #include 34 | 35 | class DDConvexHullCmd : public MPxCommand 36 | { 37 | public: 38 | MStatus doIt( const MArgList& args ); 39 | static void* creator(); 40 | private: 41 | MString dbl_to_string(double x); 42 | MString int_to_string(int x); 43 | }; 44 | 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /DDConvexHullNode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // DDConvexHullNode.cpp 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 12/30/12. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | #include "DDConvexHullNode.h" 30 | #include "DDConvexHullUtils.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | // Attribute definitions 49 | MObject DDConvexHullNode::inputAttr; 50 | MObject DDConvexHullNode::inputComponentsAttr; 51 | MObject DDConvexHullNode::inputPolymeshAttr; 52 | MObject DDConvexHullNode::outputPolymeshAttr; 53 | MObject DDConvexHullNode::useSkinWidthAttr; 54 | MObject DDConvexHullNode::skinWidthAttr; 55 | MObject DDConvexHullNode::normalEpsilonAttr; 56 | MObject DDConvexHullNode::useTrianglesAttr; 57 | MObject DDConvexHullNode::maxOutputVerticesAttr; 58 | MObject DDConvexHullNode::useReverseTriOrderAttr; 59 | 60 | 61 | // Maya Node ID 62 | MTypeId DDConvexHullNode::id(0x7FFFF); 63 | 64 | 65 | // Constructor / destructor 66 | DDConvexHullNode::DDConvexHullNode(){} 67 | DDConvexHullNode::~DDConvexHullNode(){} 68 | 69 | 70 | void* DDConvexHullNode::creator() 71 | { 72 | return new DDConvexHullNode; 73 | } 74 | 75 | 76 | MStatus DDConvexHullNode::initialize() 77 | { 78 | MStatus stat; 79 | 80 | // InputPolymesh 81 | MFnTypedAttribute inputPolymeshAttrFn; 82 | inputPolymeshAttr = inputPolymeshAttrFn.create("inputPolymesh", "ip", 83 | MFnData::kMesh, &stat); 84 | inputPolymeshAttrFn.setDisconnectBehavior(MFnAttribute::kDelete); 85 | inputPolymeshAttrFn.setKeyable(false); 86 | 87 | // Input Components 88 | MFnTypedAttribute inputComponentsAttrFn; 89 | inputComponentsAttr = inputComponentsAttrFn.create("inputComponents", 90 | "ics", MFnData::kComponentList); 91 | inputComponentsAttrFn.setDisconnectBehavior(MFnAttribute::kReset); 92 | inputPolymeshAttrFn.setKeyable(false); 93 | 94 | // Setup the compound attr as array called input, with polymesh and 95 | // component inputs as children 96 | MFnCompoundAttribute inputAttrFn; 97 | inputAttr = inputAttrFn.create("input", "input"); 98 | inputAttrFn.addChild(inputPolymeshAttr); 99 | inputAttrFn.addChild(inputComponentsAttr); 100 | inputAttrFn.setArray(true); 101 | inputAttrFn.setIndexMatters(false); 102 | 103 | // Output 104 | MFnTypedAttribute outputPolymeshAttrFn; 105 | outputPolymeshAttr = outputPolymeshAttrFn.create("output", "out", 106 | MFnData::kMesh, &stat); 107 | if (stat != MStatus::kSuccess) 108 | { 109 | return stat; 110 | } 111 | outputPolymeshAttrFn.setWritable(false); 112 | outputPolymeshAttrFn.setStorable(false); 113 | outputPolymeshAttrFn.setKeyable(false); 114 | 115 | // Skin Width Attrs 116 | MFnNumericAttribute useSkinWidthAttrFn; 117 | useSkinWidthAttr = useSkinWidthAttrFn.create("skinWidthEnabled","skwen", 118 | MFnNumericData::kBoolean, 119 | false, &stat); 120 | useSkinWidthAttrFn.setWritable(true); 121 | useSkinWidthAttrFn.setStorable(true); 122 | useSkinWidthAttrFn.setKeyable(true); 123 | useSkinWidthAttrFn.setDefault(false); 124 | 125 | MFnNumericAttribute skinWidthFn; 126 | skinWidthAttr = skinWidthFn.create("skinWidth", "skw", 127 | MFnNumericData::kDouble, .01f, &stat); 128 | skinWidthFn.setWritable(true); 129 | skinWidthFn.setStorable(true); 130 | skinWidthFn.setKeyable(true); 131 | skinWidthFn.setDefault(0.01f); 132 | 133 | // Normal Epsilon 134 | MFnNumericAttribute normalEpsilonAttrFn; 135 | normalEpsilonAttr = normalEpsilonAttrFn.create("normalEpsilon", "ep", 136 | MFnNumericData::kDouble, 137 | .001f, &stat); 138 | normalEpsilonAttrFn.setWritable(true); 139 | normalEpsilonAttrFn.setStorable(true); 140 | normalEpsilonAttrFn.setKeyable(true); 141 | normalEpsilonAttrFn.setDefault(0.001f); 142 | normalEpsilonAttrFn.setMin(0.000001f); 143 | 144 | // Force usage of triangles 145 | // NOTE: As far as I can tell, the hulls always seem to come in already 146 | // triangulated. The code looks to read as only "report" as tris 147 | // instead of as polys. Not sure what the difference is here, so 148 | // for now, the attribute is hidden and defaulting to true. 149 | MFnNumericAttribute useTrianglesAttrFn; 150 | useTrianglesAttr = useSkinWidthAttrFn.create("forceTriangles","tri", 151 | MFnNumericData::kBoolean, 152 | true, &stat); 153 | useTrianglesAttrFn.setWritable(true); 154 | useTrianglesAttrFn.setStorable(true); 155 | useTrianglesAttrFn.setKeyable(true); 156 | useTrianglesAttrFn.setDefault(true); 157 | useTrianglesAttrFn.setHidden(true); 158 | 159 | // Maximum number of output verts attr 160 | MFnNumericAttribute maxOutputVerticesAttrFn; 161 | maxOutputVerticesAttr = maxOutputVerticesAttrFn.create("maxVertices", "max", 162 | MFnNumericData::kInt, 163 | 4096, &stat); 164 | maxOutputVerticesAttrFn.setWritable(true); 165 | maxOutputVerticesAttrFn.setStorable(true); 166 | maxOutputVerticesAttrFn.setKeyable(true); 167 | maxOutputVerticesAttrFn.setDefault(4096); 168 | maxOutputVerticesAttrFn.setMin(4); 169 | 170 | // Reverse Triangle Order 171 | MFnNumericAttribute useReverseTriOrderAttrFn; 172 | useReverseTriOrderAttr = useReverseTriOrderAttrFn.create("reverseNormals", 173 | "rev", MFnNumericData::kBoolean, 174 | false, &stat); 175 | useReverseTriOrderAttrFn.setWritable(true); 176 | useReverseTriOrderAttrFn.setStorable(true); 177 | useReverseTriOrderAttrFn.setKeyable(true); 178 | useReverseTriOrderAttrFn.setDefault(false); 179 | 180 | 181 | // Add the attributes 182 | addAttribute(useSkinWidthAttr); 183 | addAttribute(skinWidthAttr); 184 | addAttribute(normalEpsilonAttr); 185 | addAttribute(useTrianglesAttr); 186 | addAttribute(maxOutputVerticesAttr); 187 | addAttribute(useReverseTriOrderAttr); 188 | addAttribute(inputAttr); 189 | addAttribute(outputPolymeshAttr); 190 | 191 | // Setup attribute relationships 192 | attributeAffects(useSkinWidthAttr, outputPolymeshAttr); 193 | attributeAffects(skinWidthAttr, outputPolymeshAttr); 194 | attributeAffects(normalEpsilonAttr, outputPolymeshAttr); 195 | attributeAffects(useTrianglesAttr, outputPolymeshAttr); 196 | attributeAffects(maxOutputVerticesAttr, outputPolymeshAttr); 197 | attributeAffects(useReverseTriOrderAttr, outputPolymeshAttr); 198 | attributeAffects(inputAttr, outputPolymeshAttr); 199 | attributeAffects(inputPolymeshAttr, outputPolymeshAttr); 200 | attributeAffects(inputComponentsAttr, outputPolymeshAttr); 201 | return MStatus::kSuccess; 202 | } 203 | 204 | MStatus DDConvexHullNode::processInputIndex(MPointArray &allPoints, 205 | MDataHandle &meshHndl, 206 | MDataHandle &compHndl) 207 | { 208 | MObject curMesh = meshHndl.asMeshTransformed(); 209 | MObject curComps = compHndl.data(); 210 | 211 | // Need a mesh plug for comps to work 212 | if (curMesh.isNull()) 213 | { 214 | return MStatus::kFailure; 215 | } 216 | 217 | // Create the function set for meshes and query for the points 218 | MFnMesh curMeshFn(curMesh); 219 | MPointArray meshPoints; 220 | curMeshFn.getPoints(meshPoints); 221 | 222 | // Assume we have a mesh here. If the comps are null, then that 223 | // is fine, we're using the whole mesh 224 | if (curComps.isNull()) 225 | { 226 | uint numPoints = meshPoints.length(); 227 | for (uint i=0; i < numPoints; i++) 228 | { 229 | allPoints.append(meshPoints[i]); 230 | } 231 | } 232 | else 233 | { 234 | // Get the single-indexed components, convert to points, then 235 | // upload the values to the master points array (allPoints) 236 | MFnComponentListData compListFn(curComps); 237 | uint compListLen = compListFn.length(); 238 | for (uint i=0; i < compListLen; i++) 239 | { 240 | MObject component = compListFn[i]; 241 | 242 | // Make sure its a vert, face, edge, or UV 243 | if (!component.hasFn(MFn::kSingleIndexedComponent)) 244 | { 245 | continue; 246 | } 247 | 248 | // Check if the component is complete. If so, push all the points 249 | // for the mesh into the allPoints list 250 | MFnSingleIndexedComponent compFn(component); 251 | if (compFn.isComplete()) 252 | { 253 | uint numPoints = meshPoints.length(); 254 | for (uint j=0; j < numPoints; j++) 255 | { 256 | allPoints.append(meshPoints[j]); 257 | } 258 | continue; 259 | } 260 | else 261 | { 262 | MIntArray vertIndices; 263 | MStatus stat = MStatus::kSuccess; 264 | stat = DDConvexHullUtils::componentToVertexIDs(vertIndices, 265 | curMesh, 266 | component); 267 | if (stat == MStatus::kNotImplemented) 268 | { 269 | continue; 270 | } 271 | else if (stat == MStatus::kFailure) 272 | { 273 | return stat; 274 | } 275 | 276 | // Lookup the points and append to the list 277 | uint vertIndicesLen = vertIndices.length(); 278 | for (uint j=0; j < vertIndicesLen; j++) 279 | { 280 | MPoint point; 281 | curMeshFn.getPoint(vertIndices[j],point); 282 | allPoints.append(point); 283 | } 284 | } 285 | } 286 | } 287 | 288 | return MStatus::kSuccess; 289 | } 290 | 291 | MStatus DDConvexHullNode::compute(const MPlug &plug, MDataBlock &data) 292 | { 293 | MStatus stat; 294 | if (plug == outputPolymeshAttr) 295 | { 296 | // Create output MObject 297 | MFnMeshData outputDataCreator; 298 | MObject outputMesh = outputDataCreator.create(&stat); 299 | if (stat != MStatus::kSuccess) 300 | { 301 | return stat; 302 | } 303 | 304 | // Get the output data handle 305 | MDataHandle outputData = data.outputValue(outputPolymeshAttr, &stat); 306 | if (stat != MStatus::kSuccess) 307 | { 308 | return stat; 309 | } 310 | 311 | 312 | // Get the data from the input compound 313 | MPointArray allPoints; 314 | MArrayDataHandle inputData(data.inputArrayValue(inputAttr, &stat)); 315 | uint elemCount = inputData.elementCount(); 316 | if (elemCount == 0) 317 | { 318 | return MStatus::kInvalidParameter; 319 | } 320 | for (uint i=0; i < elemCount; i++) 321 | { 322 | MDataHandle curElem = inputData.inputValue(); 323 | MDataHandle meshHndl = curElem.child(inputPolymeshAttr); 324 | MDataHandle compHndl = curElem.child(inputComponentsAttr); 325 | MStatus result = processInputIndex(allPoints, meshHndl, compHndl); 326 | if (result == MStatus::kFailure) 327 | { 328 | return result; 329 | } 330 | inputData.next(); 331 | } 332 | 333 | // Ensure we have verts. If not, display a warning, and return success 334 | uint pointCount = allPoints.length(); 335 | if (pointCount < 8) 336 | { 337 | MGlobal::displayError("At least 8 unique points are required " \ 338 | "to compute the hull."); 339 | return MStatus::kFailure; 340 | } 341 | 342 | // Create the hull options and get the values from the attributes 343 | DDConvexHullUtils::hullOpts hullOptions; 344 | 345 | // Skin Width 346 | MDataHandle useSkinWidthData(data.inputValue(useSkinWidthAttr, &stat)); 347 | if (stat != MStatus::kSuccess) 348 | { 349 | return stat; 350 | } 351 | hullOptions.useSkinWidth = useSkinWidthData.asBool(); 352 | 353 | MDataHandle skinWidthData(data.inputValue(skinWidthAttr, &stat)); 354 | if (stat != MStatus::kSuccess) 355 | { 356 | return stat; 357 | } 358 | hullOptions.skinWidth = skinWidthData.asDouble(); 359 | 360 | // Epsilon 361 | MDataHandle normalEpsilonData(data.inputValue(normalEpsilonAttr,&stat)); 362 | if (stat != MStatus::kSuccess) 363 | { 364 | return stat; 365 | } 366 | hullOptions.normalEpsilon = normalEpsilonData.asDouble(); 367 | 368 | // Force Triangles 369 | MDataHandle useTrianglesData(data.inputValue(useTrianglesAttr, &stat)); 370 | if (stat != MStatus::kSuccess) 371 | { 372 | return stat; 373 | } 374 | hullOptions.forceTriangles = useTrianglesData.asBool(); 375 | 376 | // Output verts 377 | MDataHandle maxOutputVertData(data.inputValue(maxOutputVerticesAttr, 378 | &stat)); 379 | if (stat != MStatus::kSuccess) 380 | { 381 | return stat; 382 | } 383 | hullOptions.maxOutputVertices = maxOutputVertData.asInt(); 384 | 385 | // Reverse Triangles 386 | MDataHandle useRevTriData(data.inputValue(useReverseTriOrderAttr, 387 | &stat)); 388 | if (stat != MStatus::kSuccess) 389 | { 390 | return stat; 391 | } 392 | hullOptions.reverseTriangleOrder = useRevTriData.asBool(); 393 | 394 | // Generate the hull 395 | stat = DDConvexHullUtils::generateMayaHull(outputMesh, 396 | allPoints, 397 | hullOptions); 398 | 399 | if (stat != MStatus::kSuccess) 400 | { 401 | return stat; 402 | } 403 | 404 | outputData.set(outputMesh); 405 | data.setClean(outputPolymeshAttr); 406 | } 407 | else 408 | { 409 | return MStatus::kUnknownParameter; 410 | } 411 | return MStatus::kSuccess; 412 | } -------------------------------------------------------------------------------- /DDConvexHullNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // DDConvexHullNode.h 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 12/30/12. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | #ifndef __DDConvexHull__DDConvexHullNode__ 30 | #define __DDConvexHull__DDConvexHullNode__ 31 | 32 | #include "StanHull/hull.h" 33 | #include 34 | #include 35 | #include 36 | 37 | class DDConvexHullNode : public MPxNode 38 | { 39 | public: 40 | DDConvexHullNode(); 41 | virtual ~DDConvexHullNode(); 42 | 43 | // declare the compute() function 44 | virtual MStatus compute( const MPlug& plug, MDataBlock& data ); 45 | 46 | // declare a function that returns an instance of this object 47 | static void* creator(); 48 | 49 | // declare the initialize() function. Function 50 | // called when Node is initially registered. 51 | // Sets up the Node's attributes. 52 | static MStatus initialize(); 53 | 54 | // Node id for this guy 55 | static MTypeId id; 56 | 57 | // Attribute object handles 58 | static MObject useSkinWidthAttr; 59 | static MObject skinWidthAttr; 60 | static MObject normalEpsilonAttr; 61 | static MObject useTrianglesAttr; 62 | static MObject maxOutputVerticesAttr; 63 | static MObject useReverseTriOrderAttr; 64 | static MObject inputAttr; 65 | static MObject inputComponentsAttr; 66 | static MObject inputPolymeshAttr; 67 | static MObject outputPolymeshAttr; 68 | 69 | private: 70 | MStatus processInputIndex(MPointArray &allPoints, 71 | MDataHandle &meshHndl, 72 | MDataHandle &compHndl); 73 | }; 74 | 75 | 76 | #endif /* defined(__DDConvexHull__DDConvexHullNode__) */ 77 | -------------------------------------------------------------------------------- /DDConvexHullPlugin.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // DDConvexHullPlugin.cpp 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 12/30/12. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | #include 30 | #include "DDConvexHullNode.h" 31 | #include "DDConvexHullCmd.h" 32 | 33 | MStatus initializePlugin(MObject obj) 34 | { 35 | MFnPlugin plugin(obj, "DigitalDestructo", "1.0", "Any"); 36 | plugin.registerNode("DDConvexHull", 37 | DDConvexHullNode::id, 38 | DDConvexHullNode::creator, 39 | DDConvexHullNode::initialize); 40 | //plugin.registerCommand("DDConvexHull", DDConvexHullCmd::creator); 41 | return MS::kSuccess; 42 | } 43 | 44 | MStatus uninitializePlugin( MObject obj ) 45 | { 46 | MFnPlugin plugin( obj ); 47 | plugin.deregisterNode(DDConvexHullNode::id); 48 | //plugin.deregisterCommand("DDConvexHull"); 49 | return MS::kSuccess; 50 | } 51 | -------------------------------------------------------------------------------- /DDConvexHullUtils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // DDConvexHullUtils.cpp 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 1/28/13. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | #include "DDConvexHullUtils.h" 30 | #include "StanHull/hull.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | MString DDConvexHullUtils::dbl_to_string(double x) 38 | { 39 | std::ostringstream ss; 40 | ss << x; 41 | return MString((ss.str()).c_str()); 42 | } 43 | 44 | MString DDConvexHullUtils::int_to_string(int x) 45 | { 46 | std::ostringstream ss; 47 | ss << x; 48 | return MString((ss.str()).c_str()); 49 | } 50 | 51 | MStatus DDConvexHullUtils::generateMayaHull(MObject &output, 52 | const MObject &input, 53 | const DDConvexHullUtils::hullOpts &hullOptions) 54 | { 55 | // Convert the input mobject to mfnmesh 56 | if (!input.hasFn(MFn::kMesh)) 57 | { 58 | return MStatus::kInvalidParameter; 59 | } 60 | MFnMesh inputMesh(input); 61 | 62 | // Allocate an array for the vertices and fill it with the data extracted 63 | // from the input mesh 64 | uint numInputVerts = inputMesh.numVertices(); 65 | if (!numInputVerts) 66 | { 67 | return MStatus::kFailure; 68 | } 69 | 70 | MPointArray points; 71 | inputMesh.getPoints(points); 72 | 73 | return generateMayaHull(output, points, hullOptions); 74 | } 75 | 76 | MStatus DDConvexHullUtils::generateMayaHull(MObject &output, 77 | const MPointArray &vertices, 78 | const DDConvexHullUtils::hullOpts &hullOptions) 79 | { 80 | // Allocate and push the vert list into the new array Mem Cleanup req. 81 | uint numInputVerts = vertices.length(); 82 | double *inputVerts = new double[numInputVerts*3]; 83 | for (uint i=0; i < numInputVerts; i++) 84 | { 85 | uint offset = i*3; 86 | inputVerts[offset] = vertices[i].x; 87 | inputVerts[offset+1] = vertices[i].y; 88 | inputVerts[offset+2] = vertices[i].z; 89 | } 90 | 91 | // Setup the flags 92 | uint hullFlags = QF_DEFAULT; 93 | if (hullOptions.forceTriangles) 94 | { 95 | hullFlags |= QF_TRIANGLES; 96 | } 97 | if (hullOptions.useSkinWidth) 98 | { 99 | hullFlags |= QF_SKIN_WIDTH; 100 | } 101 | if (hullOptions.reverseTriangleOrder) 102 | { 103 | hullFlags |= QF_REVERSE_ORDER; 104 | } 105 | 106 | // Create the description 107 | HullDesc hullDescription; 108 | hullDescription.mFlags = hullFlags; 109 | hullDescription.mMaxVertices = hullOptions.maxOutputVertices; 110 | hullDescription.mSkinWidth = hullOptions.skinWidth; 111 | hullDescription.mNormalEpsilon = hullOptions.normalEpsilon; 112 | hullDescription.mVertexStride = sizeof(double)*3; 113 | hullDescription.mVcount = numInputVerts; 114 | hullDescription.mVertices = inputVerts; 115 | 116 | // Create the hull 117 | HullLibrary hullComputer; 118 | HullResult hullResult; 119 | HullError err = hullComputer.CreateConvexHull(hullDescription, hullResult); 120 | MStatus hullStat = MStatus::kSuccess; 121 | if (err == QE_OK) 122 | { 123 | // Grab the verts 124 | MPointArray outPoints; 125 | for (uint i=0; i < hullResult.mNumOutputVertices; i++) 126 | { 127 | uint offset = i*3; 128 | MPoint curPoint(hullResult.mOutputVertices[offset], 129 | hullResult.mOutputVertices[offset+1], 130 | hullResult.mOutputVertices[offset+2]); 131 | outPoints.append(curPoint); 132 | } 133 | 134 | // Check if the results are in polygons, or triangles. Depending on 135 | // which for the result is in, the way the face indices are setup 136 | // is different. 137 | MIntArray polyCounts; 138 | MIntArray vertexConnects; 139 | 140 | if (hullResult.mPolygons) 141 | { 142 | const uint *idx = hullResult.mIndices; 143 | for (uint i=0; i < hullResult.mNumFaces; i++) 144 | { 145 | uint pCount = *idx++; 146 | polyCounts.append(pCount); 147 | 148 | for (uint j=0; j < pCount; j++) 149 | { 150 | uint val = idx[0]; 151 | vertexConnects.append(val); 152 | idx++; 153 | } 154 | } 155 | } 156 | else 157 | { 158 | polyCounts.setLength(hullResult.mNumFaces); 159 | for (uint i=0; i < hullResult.mNumFaces; i++) 160 | { 161 | 162 | polyCounts[i] = 3; 163 | uint *idx = &hullResult.mIndices[i*3]; 164 | 165 | vertexConnects.append(idx[0]); 166 | vertexConnects.append(idx[1]); 167 | vertexConnects.append(idx[2]); 168 | } 169 | } 170 | // Setup the outmesh 171 | MFnMesh outMeshFn(output); 172 | outMeshFn.create(hullResult.mNumOutputVertices, 173 | hullResult.mNumFaces, 174 | outPoints, 175 | polyCounts, 176 | vertexConnects, 177 | output, 178 | &hullStat); 179 | } 180 | else 181 | { 182 | hullStat = MStatus::kFailure; 183 | } 184 | 185 | // Mem Cleanup 186 | hullComputer.ReleaseResult(hullResult); 187 | delete[] inputVerts; 188 | 189 | return hullStat; 190 | } 191 | 192 | MStatus DDConvexHullUtils::componentToVertexIDs(MIntArray &outIndices, 193 | const MObject &mesh, 194 | const MObject &component) 195 | { 196 | // Create the funciton sets 197 | MFnSingleIndexedComponent compFn(component); 198 | MFnMesh meshFn(mesh); 199 | 200 | MIntArray elems; 201 | compFn.getElements(elems); 202 | uint elemLen = elems.length(); 203 | 204 | // Convert the components to vertices based on component type 205 | uint compType = compFn.componentType(); 206 | if (compType == MFn::kMeshVertComponent) 207 | { 208 | outIndices = elems; 209 | } 210 | else if (compType == MFn::kMeshEdgeComponent) 211 | { 212 | for (uint i=0; i < elemLen; i++) 213 | { 214 | int2 edgeVerts; 215 | meshFn.getEdgeVertices(elems[i], edgeVerts); 216 | outIndices.append(edgeVerts[0]); 217 | outIndices.append(edgeVerts[1]); 218 | } 219 | } 220 | else if (compType == MFn::kMeshPolygonComponent) 221 | { 222 | for (uint i=0; i < elemLen; i++) 223 | { 224 | // Grab verts for the current poly 225 | MIntArray polyVerts; 226 | meshFn.getPolygonVertices(elems[i], polyVerts); 227 | uint polyVertsLen = polyVerts.length(); 228 | for (uint j=0; j < polyVertsLen; j++) 229 | { 230 | outIndices.append(polyVerts[j]); 231 | } 232 | } 233 | } 234 | else if (compType == MFn::kMeshFaceVertComponent) 235 | { 236 | // I think this is how you convert face to object 237 | // relative vertices... 238 | MIntArray faceCounts; 239 | MIntArray faceVerts; 240 | meshFn.getVertices(faceCounts, faceVerts); 241 | for (uint j=0; j < elemLen; j++) 242 | { 243 | outIndices.append(faceVerts[j]); 244 | } 245 | } 246 | else 247 | { 248 | // Not supported 249 | return MStatus::kNotImplemented; 250 | } 251 | return MStatus::kSuccess; 252 | } -------------------------------------------------------------------------------- /DDConvexHullUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // DDConvexHullUtils.h 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 1/28/13. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | #ifndef __DDConvexHull__DDConvexHullUtils__ 30 | #define __DDConvexHull__DDConvexHullUtils__ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace DDConvexHullUtils 39 | {; 40 | struct hullOpts 41 | { 42 | // Create a constructor with default values 43 | hullOpts() : forceTriangles(false), 44 | maxOutputVertices(4096), 45 | useSkinWidth(false), 46 | skinWidth(0.01f), 47 | normalEpsilon(0.001f), 48 | reverseTriangleOrder(false) {} 49 | 50 | bool forceTriangles; 51 | uint maxOutputVertices; 52 | bool useSkinWidth; 53 | double skinWidth; 54 | double normalEpsilon; 55 | bool reverseTriangleOrder; 56 | }; 57 | 58 | MStatus generateMayaHull(MObject &output, 59 | const MPointArray &vertices, 60 | const hullOpts &hullOptions); 61 | 62 | MStatus generateMayaHull(MObject &output, 63 | const MObject &input, 64 | const hullOpts &hullOptions); 65 | 66 | MStatus componentToVertexIDs(MIntArray &outIndices, 67 | const MObject &mesh, 68 | const MObject &component); 69 | 70 | MString dbl_to_string(double x); 71 | MString int_to_string(int x); 72 | }; 73 | 74 | #endif /* defined(__DDConvexHull__DDConvexHullUtils__) */ 75 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jonathan Tilden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Models/stanfordbunny.mb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digitaldestructo/DDConvexHull/ce63a2d1b0ef150c6b777d714802cb96f5b2b0ff/Models/stanfordbunny.mb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DDConvexHull 2 | ============ 3 | 4 | A Convex Hull plug-in for Maya based on StanHull. The hard work credit goes to Stan Melax and John Ratcliff for providing the open source code that actually does the convex hull. 5 | 6 | The code should compile without issue on Windows, as it was ported from Windows to compile on OSX. 7 | -------------------------------------------------------------------------------- /Scripts/AETemplates/AEDDConvexHullTemplate.mel: -------------------------------------------------------------------------------- 1 | // 2 | // AEDDConvexHullTemplate.mel 3 | // DDConvexHull 4 | // 5 | // Created by Jonathan Tilden on 1/1/13. 6 | // 7 | // MIT License 8 | // 9 | // Copyright (c) 2017 Jonathan Tilden 10 | 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | // SOFTWARE. 28 | 29 | source AEnewNonNumericMulti.mel; 30 | 31 | // Callback when the user changes text for the input components in the 32 | // attribute edtior 33 | global proc AEDDConvexHullTemplate_updateComps(string $attr, string $value) 34 | { 35 | string $buffer[]; 36 | tokenize $value " " $buffer; 37 | print (`size $buffer` + "\n"); 38 | print $buffer; 39 | $value = ("\"" + `stringArrayToString $buffer "\" \""` + "\""); 40 | string $cmd = ("setAttr " + $attr + " -type componentList " + 41 | `size $buffer` + " " + $value); 42 | evalEcho($cmd); 43 | } 44 | 45 | // Callback for the scriptJob that runs any time the inputComponents 46 | // attribute changes while the attribute edtior has focust 47 | global proc AEDDConvexHullTemplate_updateCompsScriptJob(string $attr, 48 | string $textBox) 49 | { 50 | string $comps[] = `getAttr $attr`; 51 | string $compsStr = `stringArrayToString $comps " "`; 52 | textFieldGrp -e -tx $compsStr $textBox; 53 | } 54 | 55 | // Callback for when the add selected button is press in the 56 | // attribute editor. Calls method in DDConvexHullUtils.py 57 | global proc AEDDConvexHullTemplate_addSelected(string $nodeName) 58 | { 59 | string $buffer[]; 60 | tokenize $nodeName "." $buffer; 61 | string $python = "import DDConvexHullUtils;"; 62 | $python += ("DDConvexHullUtils.addObjects('" + $buffer[0] + "')"); 63 | python($python); 64 | } 65 | 66 | // When skin width is not enabled, disable the skin width attribute 67 | // control widget 68 | global proc AEDDConvexHullTemplate_dimSkinWidth(string $nodeName) 69 | { 70 | int $skinWidthEnabled = `getAttr ($nodeName + ".skinWidthEnabled")`; 71 | editorTemplate -dimControl $nodeName "skinWidth" (!$skinWidthEnabled); 72 | } 73 | 74 | // Creates a brand new AE Block for the Compound Array Input attribute 75 | global proc AEDDConvexHullTemplate_InputNew(string $name) 76 | { 77 | setUITemplate -pst attributeEditorTemplate; 78 | frameLayout -l "Convex Hull Inputs" AEDDConvexHullTemplate_InputFrame; 79 | 80 | setParent AEDDConvexHullTemplate_InputFrame; 81 | columnLayout -adj 1 -rs 3 AEDDConvexHullTemplate_InputVLayout; 82 | setParent ..; 83 | 84 | setParent AEDDConvexHullTemplate_InputVLayout; 85 | string $buffer[]; 86 | tokenize $name "." $buffer; 87 | string $remCmd = ("AEnewNonNumericMultiAddNewItem(\"" + 88 | $buffer[0] + "\",\"" + $buffer[1] + "\")"); 89 | string $addCmd = ("AEDDConvexHullTemplate_addSelected(\"" + $name + "\")"); 90 | string $selBtn = `button -l "Add Selected" -c $addCmd`; 91 | string $newBtn = `button -l "Add New Item" -c $remCmd`; 92 | setParent ..; 93 | 94 | setUITemplate -ppt; 95 | 96 | AEDDConvexHullTemplate_InputRepl $name; 97 | } 98 | 99 | // Creates a new section for the specified input index of the Hull 100 | // Each section displays a custom widget showing the connected mesh, 101 | // as well as a text field for displaying the active components 102 | proc newInputIndex(string $name, int $index, string $parent) 103 | { 104 | setUITemplate -pst attributeEditorTemplate; 105 | setParent $parent; 106 | 107 | string $fullName = ($name + "[" + $index + "]"); 108 | string $uiName = "input[" + $index + "]"; 109 | string $frame = `frameLayout -l $uiName -collapse 0`; 110 | setParent ..; 111 | setParent $frame; 112 | attrNavigationControlGrp -l "Input Polymesh" 113 | -at ($fullName + ".inputPolymesh"); 114 | 115 | // Represent the input components as text 116 | string $comps[] = `getAttr ($fullName + ".ics")`; 117 | string $compsStr = `stringArrayToString $comps " "`; 118 | string $chngCmd = ("AEDDConvexHullTemplate_updateComps(\"" + 119 | $fullName + ".ics\",\"#1\")"); 120 | string $textBox = `textFieldGrp -l "Input Components" 121 | -tx $compsStr -cc $chngCmd`; 122 | 123 | // Create a script job parented to the text box to update 124 | // when the attribute changes 125 | string $sjCmd = ("AEDDConvexHullTemplate_updateCompsScriptJob" + 126 | "(\"" + ($fullName + ".ics") + "\",\"" + $textBox + "\")"); 127 | print(`scriptJob -p $textBox -ac ($fullName + ".ics") $sjCmd`); 128 | print("\n"); 129 | 130 | // Create the Remove button. Nicely space it to grow from the right 131 | string $row = `rowLayout -nc 2 -adj 2`; 132 | text -l " " -w 10 -p $row; 133 | button -l ("Remove " + $uiName) -p $row 134 | -c ("AEremoveMultiElement(\""+$fullName+"\")"); 135 | setParent ..; 136 | setUITemplate -ppt; 137 | } 138 | 139 | // Updates the Input block of the AE Template. Note that every time, 140 | // each compound index attribute is destroyed, then recreated. 141 | global proc AEDDConvexHullTemplate_InputRepl(string $name) 142 | { 143 | // Delete the framelayouts 144 | setUITemplate -pst attributeEditorTemplate; 145 | string $children[] = `columnLayout -q -ca 146 | AEDDConvexHullTemplate_InputVLayout`; 147 | for ($child in $children) 148 | { 149 | if (`objectTypeUI $child` == "frameLayout") 150 | deleteUI -lay $child; 151 | } 152 | 153 | // Remove the duplicate elements in the array that show up 154 | int $allIndices[] = `getAttr -multiIndices $name`; 155 | int $visited[]; 156 | int $indices[]; 157 | for ($index in $allIndices) 158 | { 159 | int $dupe = 0; 160 | for ($idx in $visited) 161 | { 162 | if ($index == $idx) 163 | { 164 | $dupe = 1; 165 | break; 166 | } 167 | } 168 | if (!$dupe) 169 | { 170 | $visited[`size $visited`] = $index; 171 | $indices[`size $indices`] = $index; 172 | } 173 | } 174 | 175 | // Make each section 176 | for ($i=0; $i < `size $indices`; $i++) 177 | { 178 | newInputIndex $name $indices[$i] "AEDDConvexHullTemplate_InputVLayout"; 179 | } 180 | setUITemplate -ppt; 181 | } 182 | 183 | // Main entry point for the AE Template 184 | global proc AEDDConvexHullTemplate(string $nodeName) 185 | { 186 | editorTemplate -beginScrollLayout; 187 | editorTemplate -beginLayout "Convex Hull Attributes" -collapse 0; 188 | editorTemplate -addControl "maxVertices"; 189 | editorTemplate -addControl "reverseNormals"; 190 | editorTemplate -addControl "normalEpsilon"; 191 | 192 | // Hide the forceTriangles attribute that doesn't seem 193 | // to do anything 194 | editorTemplate -suppress "forceTriangles"; 195 | 196 | 197 | // Skin Width block 198 | editorTemplate -addSeparator; 199 | editorTemplate -addControl "skinWidth"; 200 | editorTemplate -addControl "skinWidthEnabled" 201 | "AEDDConvexHullTemplate_dimSkinWidth"; 202 | 203 | // Input block 204 | editorTemplate -callCustom "AEDDConvexHullTemplate_InputNew" 205 | "AEDDConvexHullTemplate_InputRepl" 206 | "input"; 207 | 208 | editorTemplate -endLayout; 209 | 210 | // include/call base class/node attributes 211 | AEdependNodeTemplate $nodeName; 212 | 213 | editorTemplate -addExtraControls; 214 | editorTemplate -endScrollLayout; 215 | } 216 | -------------------------------------------------------------------------------- /Scripts/DDConvexHullUtils.py: -------------------------------------------------------------------------------- 1 | # 2 | # DDConvexHullUtils.py 3 | # DDConvexHull 4 | # 5 | # Created by Jonathan Tilden on 1/1/13. 6 | # 7 | # MIT License 8 | # 9 | # Copyright (c) 2017 Jonathan Tilden 10 | 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documentation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furnished to do so, subject to the following conditions: 17 | 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | # SOFTWARE. 28 | 29 | __author__ = 'Jonathan Tilden' 30 | __doc__ = """A collection of useful utilities for use with the DDConvexHull 31 | plugin for Maya.""" 32 | 33 | import maya.cmds as cmds 34 | import maya.mel as mel 35 | import re 36 | 37 | _INDEX_RE = re.compile("\[(?P[0-9])+\]") 38 | 39 | class DDConvexHullException(RuntimeError): 40 | pass 41 | 42 | def _determineMeshNode(node): 43 | """ 44 | Given the specified node, return the associated mesh. If no node can 45 | be determined, then a None type is returned. 46 | """ 47 | # Scan for all node types that inherit from mesh or transform, just in 48 | # case there are weird custom nodes in the pipeline. 49 | types = cmds.nodeType(node, i=True) 50 | if ('transform' in types): 51 | shapes = cmds.listRelatives(node, s=True, f=True, type='mesh') 52 | if shapes is None or not len(shapes): 53 | return None 54 | 55 | # Workaround for a bug in 2011 where -ni flag for listRelatives didn't 56 | # work as advertised. 57 | shapes = cmds.ls(shapes, l=True, ni=True) 58 | if shapes is None or not len(shapes): 59 | return None 60 | 61 | # If here, take the first node 62 | return shapes[0] 63 | elif ('mesh' in types): 64 | return node 65 | else: 66 | return None 67 | return None 68 | 69 | def _splitattr(attr): 70 | """ 71 | Splits the attr string into obj/attr tuple. 72 | 73 | NOTE: Only the first '.' will be split and returned 74 | ex. _splitattr(ball.foo.bar) returns ('ball','foo.bar') 75 | """ 76 | tokens = attr.split('.') 77 | if len(tokens) > 1: 78 | return (tokens[0], '.'.join(tokens[1:])) 79 | return (tokens[0], "") 80 | 81 | def _attrindex(attr): 82 | """ 83 | Parses the attr string and returns the first index it finds. 84 | ex. _attrindex('foo.input[0].ics') returns 0 85 | """ 86 | result = _INDEX_RE.search(attr) 87 | if result is not None: 88 | return int(result.group('index')) 89 | 90 | def _getFirstEmptyInputIndex(convexHullNode, limit=32): 91 | """ 92 | Returns the first empty input index from the specified convex hull node. 93 | The limit flag simply specifies when to stop checking for an empty index 94 | and return -1. 95 | """ 96 | multiIndices = cmds.getAttr('%s.input' % convexHullNode, multiIndices=True) 97 | if multiIndices is None: 98 | return 0 99 | indices = set(multiIndices) 100 | for idx in xrange(0, limit): 101 | if not idx in indices: 102 | return idx 103 | return -1 104 | 105 | def _optimizeComponentList(mesh, componentList): 106 | """ 107 | Given the specified mesh and its list of components, return a list that 108 | represents the most optimized representation of the components. 109 | ex. ['vtx[10]','vtx[11]'] optimizes to ['vtx[10:11]'] 110 | """ 111 | vertices = [] 112 | faces = [] 113 | edges = [] 114 | for comp in componentList: 115 | if comp.startswith('f['): 116 | toAdd = faces 117 | elif comp.startswith('vtx['): 118 | toAdd = vertices 119 | elif comp.startswith('e['): 120 | toAdd = edges 121 | else: 122 | mel.eval('warning "Unsupported component type: %s"' % comp) 123 | continue 124 | toAdd.append('%s.%s' % (mesh, comp)) 125 | newCompList = [] 126 | if len(vertices): 127 | newComps = cmds.polyListComponentConversion(vertices, tv=True) 128 | if newComps is not None: 129 | newCompList.extend(newComps) 130 | if len(faces): 131 | newComps = cmds.polyListComponentConversion(faces, tf=True) 132 | if newComps is not None: 133 | newCompList.extend(newComps) 134 | if len(edges): 135 | newComps = cmds.polyListComponentConversion(edges, te=True) 136 | if newComps is not None: 137 | newCompList.extend(newComps) 138 | return [x.split('.')[-1] for x in newCompList] 139 | 140 | 141 | def setComponents(componentList, convexHullNode, index, 142 | preserveExisting=True, optimize=True): 143 | """ 144 | Given a list of components (in the form of ['f[0]','vtx[23:67]', ...]), set 145 | the specified, indexed componentList attribute for the convex hull. 146 | 147 | If preserveExisting is True, the any components that are already on the 148 | attribute will be preserved. Otherwise, they will be overwritten. 149 | 150 | If optimize is set to True, convert the list of components into the more 151 | compact form that Maya typically expects. 152 | """ 153 | inputAttr = '%s.input[%d]' % (convexHullNode, index) 154 | if preserveExisting: 155 | comps = cmds.getAttr('%s.ics' % inputAttr) 156 | if comps is not None: 157 | componentList.extend(comps) 158 | if optimize: 159 | attr = '%s.input' 160 | mesh = cmds.connectionInfo('%s.inputPolymesh' % inputAttr, 161 | sfd=True, dfs=False) 162 | if mesh is None or mesh == '': 163 | mel.eval('warning "Unable to determine connected to ' \ 164 | '%s.inputPolymesh' % inputAttr) 165 | else: 166 | meshName, plug = _splitattr(mesh) 167 | componentList = _optimizeComponentList(meshName, componentList) 168 | 169 | # Flatten the list to a space-delimited string 170 | numComponents = len(componentList) 171 | print componentList 172 | cmds.setAttr('%s.ics' % inputAttr, 173 | numComponents, type='componentList', *componentList) 174 | 175 | 176 | def getConnectedMeshes(convexHullNode, reverseMapping=False): 177 | """ 178 | Returns a dictionary mapping the array index to the mesh connected to the 179 | input[x].inputPolymesh attribute. 180 | ex. {0 : 'myMeshShape', 2 : 'myBallShape'} 181 | If reverse mapping is True, the connected mesh maps to the indices. 182 | ex. {'myMeshShape' : [0], {'myBallShape' : [2,3]} 183 | """ 184 | inputAttr = '%s.input' % convexHullNode 185 | connections = cmds.listConnections(inputAttr, sh=True, p=True, 186 | type='mesh', c=True) 187 | if connections is None or not len(connections): 188 | return {} 189 | 190 | # The convex node is always on the left, connection on right. 191 | mapping = {} 192 | for idx in xrange(0, len(connections), 2): 193 | if connections[idx].find('.inputPolymesh') == -1: 194 | continue 195 | index = _attrindex(connections[idx]) 196 | mesh = _splitattr(connections[idx+1]) 197 | mesh = cmds.ls(mesh, l=True)[0] 198 | if reverseMapping: 199 | if not mapping.has_key(mesh): 200 | mapping[mesh] = [] 201 | mapping[mesh].append(index) 202 | else: 203 | mapping[index] = mesh 204 | return mapping 205 | 206 | def connectMesh(convexHullNode, meshNode, componentList=[]): 207 | """ 208 | Connects the specified mesh and components to the convex hull node. 209 | 210 | NOTE: New connections are always made 211 | """ 212 | # Find the first empty index 213 | idx = _getFirstEmptyInputIndex(convexHullNode) 214 | cmds.connectAttr(('%s.worldMesh' % meshNode), 215 | ('%s.input[%d].inputPolymesh' % (convexHullNode,idx)), 216 | force=True) 217 | 218 | # If there are components, set them 219 | numComponents = len(componentList) 220 | if numComponents: 221 | setComponents(componentList, convexHullNode, idx) 222 | 223 | def addObjects(convexHullNode, objects=[]): 224 | """ 225 | Adds the specified objects to the convex hull node. If no objects are 226 | specified, then the user's selection is used. 227 | """ 228 | if not len(objects): 229 | objects = cmds.ls(sl=True, l=True) 230 | 231 | # Check again. If no objects specified, generate an error 232 | if not len(objects): 233 | raise DDConvexHullException, 'No objects were specified to add to ' \ 234 | 'the convex hull' 235 | 236 | # Check the node exists 237 | if not cmds.objExists(convexHullNode): 238 | raise DDConvexHullException, 'The specified convex hull %s does not ' \ 239 | 'exist.' % convexHullNode 240 | 241 | # Generate a mapping of connected meshes. Get a reverse mapping so its 242 | # easy to test if the mesh specified should be added or updated. 243 | connectedMeshes = getConnectedMeshes(convexHullNode, reverseMapping=True) 244 | 245 | # Iterate through the objects and build a map of node to components 246 | compMap = {} 247 | for obj in objects: 248 | node, comp = _splitattr(obj) 249 | mesh = _determineMeshNode(node) 250 | if not compMap.has_key(mesh): 251 | compMap[mesh] = {'update':mesh in connectedMeshes, 'components':[]} 252 | if comp != '': 253 | compMap[mesh]['components'].append(comp) 254 | for mesh in compMap: 255 | if compMap[mesh]['update']: 256 | setComponents(compMap[mesh]['components'], 257 | convexHullNode, connectedMeshes[mesh][0]) 258 | else: 259 | connectMesh(convexHullNode, mesh, compMap[mesh]['components']) 260 | 261 | def createHull(hullname='', meshname='', objects=[], createTransform=True, 262 | parent=None): 263 | """ 264 | Creates a new hull and output mesh with the specified connected objects. 265 | If no objects are specified, the user's selection is used. If 266 | createTransform is True, then the meshname will be the name of the transform 267 | and the mesh will have 'shape' appended to the end. 268 | 269 | Returns a tuple in the form of (hullNode, meshNode, xformNode) 270 | """ 271 | selection = cmds.ls(sl=True, l=True) 272 | 273 | hullargs = {} 274 | if hullname != '': 275 | hullargs['n'] = hullname 276 | hullNode = cmds.createNode('DDConvexHull', **hullargs) 277 | 278 | # Create a transform if specified. If so, set the mesh name to the 279 | # name of the transform 280 | xformNode = None 281 | if createTransform: 282 | xformArgs = {} 283 | if meshname == '': 284 | meshname = 'polySurface#' 285 | xformArgs['n'] = meshname 286 | if parent is not None: 287 | xformArgs['p'] = parent 288 | xformNode = cmds.createNode('transform', **xformArgs) 289 | 290 | meshargs = {} 291 | if meshname != '': 292 | meshargs['n'] = meshname 293 | if createTransform and xformNode is not None: 294 | meshargs['n'] = '%sShape' % xformNode 295 | meshargs['p'] = xformNode 296 | elif parent is not None: 297 | meshargs['p'] = parent 298 | meshNode = cmds.createNode('mesh', **meshargs) 299 | 300 | # Connect the nodes 301 | cmds.connectAttr('%s.output' % hullNode, '%s.inMesh' % meshNode) 302 | 303 | # If there are no objects specified, and no selection, handle it here 304 | # so it doesn't create an exception when passed to addObjects 305 | if not len(objects) and (selection is None or not len(selection)): 306 | mel.eval('warning "No objects specified to add to hull"') 307 | else: 308 | objects = selection 309 | addObjects(hullNode, objects=objects) 310 | return (hullNode, meshNode, xformNode) 311 | 312 | -------------------------------------------------------------------------------- /StanHull/hull.h: -------------------------------------------------------------------------------- 1 | #ifndef HUL_H 2 | 3 | #define HULL_H 4 | 5 | 6 | /*! 7 | ** 8 | ** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net 9 | ** 10 | ** Portions of this source has been released with the PhysXViewer application, as well as 11 | ** Rocket, CreateDynamics, ODF, and as a number of sample code snippets. 12 | ** 13 | ** If you find this code useful or you are feeling particularily generous I would 14 | ** ask that you please go to http://www.amillionpixels.us and make a donation 15 | ** to Troy DeMolay. 16 | ** 17 | ** DeMolay is a youth group for young men between the ages of 12 and 21. 18 | ** It teaches strong moral principles, as well as leadership skills and 19 | ** public speaking. The donations page uses the 'pay for pixels' paradigm 20 | ** where, in this case, a pixel is only a single penny. Donations can be 21 | ** made for as small as $4 or as high as a $100 block. Each person who donates 22 | ** will get a link to their own site as well as acknowledgement on the 23 | ** donations blog located here http://www.amillionpixels.blogspot.com/ 24 | ** 25 | ** If you wish to contact me you can use the following methods: 26 | ** 27 | ** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches) 28 | ** Skype ID: jratcliff63367 29 | ** Yahoo: jratcliff63367 30 | ** AOL: jratcliff1961 31 | ** email: jratcliff@infiniplex.net 32 | ** Personal website: http://jratcliffscarab.blogspot.com 33 | ** Coding Website: http://codesuppository.blogspot.com 34 | ** FundRaising Blog: http://amillionpixels.blogspot.com 35 | ** Fundraising site: http://www.amillionpixels.us 36 | ** New Temple Site: http://newtemple.blogspot.com 37 | ** 38 | ** 39 | ** The MIT license: 40 | ** 41 | ** Permission is hereby granted, free of charge, to any person obtaining a copy 42 | ** of this software and associated documentation files (the "Software"), to deal 43 | ** in the Software without restriction, including without limitation the rights 44 | ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 45 | ** copies of the Software, and to permit persons to whom the Software is furnished 46 | ** to do so, subject to the following conditions: 47 | ** 48 | ** The above copyright notice and this permission notice shall be included in all 49 | ** copies or substantial portions of the Software. 50 | 51 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 52 | ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 53 | ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 54 | ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 55 | ** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 56 | ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 57 | 58 | */ 59 | 60 | // Jtilden - on include string.h for memcpy. Works on mac and windows 61 | #include 62 | 63 | class HullResult 64 | { 65 | public: 66 | HullResult(void) 67 | { 68 | mPolygons = true; 69 | mNumOutputVertices = 0; 70 | mOutputVertices = 0; 71 | mNumFaces = 0; 72 | mNumIndices = 0; 73 | mIndices = 0; 74 | } 75 | bool mPolygons; // true if indices represents polygons, false indices are triangles 76 | unsigned int mNumOutputVertices; // number of vertices in the output hull 77 | double *mOutputVertices; // array of vertices, 3 doubles each x,y,z 78 | unsigned int mNumFaces; // the number of faces produced 79 | unsigned int mNumIndices; // the total number of indices 80 | unsigned int *mIndices; // pointer to indices. 81 | 82 | // If triangles, then indices are array indexes into the vertex list. 83 | // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc.. 84 | }; 85 | 86 | class FHullResult 87 | { 88 | public: 89 | FHullResult(const HullResult &r) 90 | { 91 | mPolygons = r.mPolygons; 92 | mNumOutputVertices = r.mNumOutputVertices; 93 | mNumFaces = r.mNumFaces; 94 | mNumIndices = r.mNumIndices; 95 | mIndices = 0; 96 | mOutputVertices = 0; 97 | if ( mNumIndices ) 98 | { 99 | mIndices = new unsigned int[mNumIndices]; 100 | memcpy(mIndices,r.mIndices,sizeof(unsigned int)*mNumIndices); 101 | } 102 | if ( mNumOutputVertices ) 103 | { 104 | mOutputVertices = new float[mNumOutputVertices*3]; 105 | const double *src = r.mOutputVertices; 106 | float *dst = mOutputVertices; 107 | for (unsigned int i=0; i 2 | #include 3 | #include 4 | #include 5 | 6 | #include "wavefront.h" 7 | #include "hull.h" 8 | 9 | // Jtilden - on mac OSX, include strings.h and redefine strnicmp 10 | #ifdef __APPLE__ 11 | #include 12 | #define strnicmp strncasecmp 13 | #define stricmp strcasecmp 14 | #endif 15 | 16 | int main(int argc,char **argv) 17 | { 18 | if ( argc < 2 ) 19 | { 20 | printf("Usage: StanHull (options)\r\n"); 21 | printf("\r\n"); 22 | printf(" must be a valid Wavefront .OBJ file\r\n"); 23 | printf("\r\n"); 24 | printf("-t output as triangles instead of polgons.\r\n"); 25 | printf("-s(n) skin width\r\n"); 26 | printf("-v(n) maximum number of vertices\r\n"); 27 | printf("-n(n) normal epsilon\r\n"); 28 | } 29 | else 30 | { 31 | char *fname = argv[1]; 32 | 33 | HullDesc desc; 34 | 35 | for (int i=2; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "wavefront.h" 8 | 9 | /*---------------------------------------------------------------------- 10 | Copyright (c) 2004 Open Dynamics Framework Group 11 | www.physicstools.org 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 15 | that the following conditions are met: 16 | 17 | Redistributions of source code must retain the above copyright notice, this list of conditions 18 | and the following disclaimer. 19 | 20 | Redistributions in binary form must reproduce the above copyright notice, 21 | this list of conditions and the following disclaimer in the documentation 22 | and/or other materials provided with the distribution. 23 | 24 | Neither the name of the Open Dynamics Framework Group nor the names of its contributors may 25 | be used to endorse or promote products derived from this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, 28 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | -----------------------------------------------------------------------*/ 35 | 36 | #include 37 | 38 | typedef std::vector< int > IntVector; 39 | typedef std::vector< float > FloatVector; 40 | 41 | namespace WAVEFRONT 42 | { 43 | 44 | #if defined(__APPLE__) || defined(__CELLOS_LV2__) 45 | #define stricmp(a, b) strcasecmp((a), (b)) 46 | #endif 47 | 48 | /*******************************************************************/ 49 | /******************** InParser.h ********************************/ 50 | /*******************************************************************/ 51 | class InPlaceParserInterface 52 | { 53 | public: 54 | virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process 55 | }; 56 | 57 | enum SeparatorType 58 | { 59 | ST_DATA, // is data 60 | ST_HARD, // is a hard separator 61 | ST_SOFT, // is a soft separator 62 | ST_EOS // is a comment symbol, and everything past this character should be ignored 63 | }; 64 | 65 | class InPlaceParser 66 | { 67 | public: 68 | InPlaceParser(void) 69 | { 70 | Init(); 71 | } 72 | 73 | InPlaceParser(char *data,int len) 74 | { 75 | Init(); 76 | SetSourceData(data,len); 77 | } 78 | 79 | InPlaceParser(const char *fname) 80 | { 81 | Init(); 82 | SetFile(fname); 83 | } 84 | 85 | ~InPlaceParser(void); 86 | 87 | void Init(void) 88 | { 89 | mQuoteChar = 34; 90 | mData = 0; 91 | mLen = 0; 92 | mMyAlloc = false; 93 | for (int i=0; i<256; i++) 94 | { 95 | mHard[i] = ST_DATA; 96 | mHardString[i*2] = i; 97 | mHardString[i*2+1] = 0; 98 | } 99 | mHard[0] = ST_EOS; 100 | mHard[32] = ST_SOFT; 101 | mHard[9] = ST_SOFT; 102 | mHard[13] = ST_SOFT; 103 | mHard[10] = ST_SOFT; 104 | } 105 | 106 | void SetFile(const char *fname); // use this file as source data to parse. 107 | 108 | void SetSourceData(char *data,int len) 109 | { 110 | mData = data; 111 | mLen = len; 112 | mMyAlloc = false; 113 | }; 114 | 115 | int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason 116 | 117 | int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback); 118 | 119 | const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse. 120 | 121 | void SetHardSeparator(char c) // add a hard separator 122 | { 123 | mHard[c] = ST_HARD; 124 | } 125 | 126 | void SetHard(char c) // add a hard separator 127 | { 128 | mHard[c] = ST_HARD; 129 | } 130 | 131 | 132 | void SetCommentSymbol(char c) // comment character, treated as 'end of string' 133 | { 134 | mHard[c] = ST_EOS; 135 | } 136 | 137 | void ClearHardSeparator(char c) 138 | { 139 | mHard[c] = ST_DATA; 140 | } 141 | 142 | 143 | void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character. 144 | 145 | bool EOS(char c) 146 | { 147 | if ( mHard[c] == ST_EOS ) 148 | { 149 | return true; 150 | } 151 | return false; 152 | } 153 | 154 | void SetQuoteChar(char c) 155 | { 156 | mQuoteChar = c; 157 | } 158 | 159 | private: 160 | 161 | 162 | inline char * AddHard(int &argc,const char **argv,char *foo); 163 | inline bool IsHard(char c); 164 | inline char * SkipSpaces(char *foo); 165 | inline bool IsWhiteSpace(char c); 166 | inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft 167 | 168 | bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it. 169 | char *mData; // ascii data to parse. 170 | int mLen; // length of data 171 | SeparatorType mHard[256]; 172 | char mHardString[256*2]; 173 | char mQuoteChar; 174 | }; 175 | 176 | /*******************************************************************/ 177 | /******************** InParser.cpp ********************************/ 178 | /*******************************************************************/ 179 | void InPlaceParser::SetFile(const char *fname) 180 | { 181 | if ( mMyAlloc ) 182 | { 183 | free(mData); 184 | } 185 | mData = 0; 186 | mLen = 0; 187 | mMyAlloc = false; 188 | 189 | 190 | FILE *fph = fopen(fname,"rb"); 191 | if ( fph ) 192 | { 193 | fseek(fph,0L,SEEK_END); 194 | mLen = ftell(fph); 195 | fseek(fph,0L,SEEK_SET); 196 | if ( mLen ) 197 | { 198 | mData = (char *) malloc(sizeof(char)*(mLen+1)); 199 | int ok = fread(mData, mLen, 1, fph); 200 | if ( !ok ) 201 | { 202 | free(mData); 203 | mData = 0; 204 | } 205 | else 206 | { 207 | mData[mLen] = 0; // zero byte terminate end of file marker. 208 | mMyAlloc = true; 209 | } 210 | } 211 | fclose(fph); 212 | } 213 | } 214 | 215 | InPlaceParser::~InPlaceParser(void) 216 | { 217 | if ( mMyAlloc ) 218 | { 219 | free(mData); 220 | } 221 | } 222 | 223 | #define MAXARGS 512 224 | 225 | bool InPlaceParser::IsHard(char c) 226 | { 227 | return mHard[c] == ST_HARD; 228 | } 229 | 230 | char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo) 231 | { 232 | while ( IsHard(*foo) ) 233 | { 234 | const char *hard = &mHardString[*foo*2]; 235 | if ( argc < MAXARGS ) 236 | { 237 | argv[argc++] = hard; 238 | } 239 | foo++; 240 | } 241 | return foo; 242 | } 243 | 244 | bool InPlaceParser::IsWhiteSpace(char c) 245 | { 246 | return mHard[c] == ST_SOFT; 247 | } 248 | 249 | char * InPlaceParser::SkipSpaces(char *foo) 250 | { 251 | while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++; 252 | return foo; 253 | } 254 | 255 | bool InPlaceParser::IsNonSeparator(char c) 256 | { 257 | if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true; 258 | return false; 259 | } 260 | 261 | 262 | int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback) 263 | { 264 | int ret = 0; 265 | 266 | const char *argv[MAXARGS]; 267 | int argc = 0; 268 | 269 | char *foo = line; 270 | 271 | while ( !EOS(*foo) && argc < MAXARGS ) 272 | { 273 | 274 | foo = SkipSpaces(foo); // skip any leading spaces 275 | 276 | if ( EOS(*foo) ) break; 277 | 278 | if ( *foo == mQuoteChar ) // if it is an open quote 279 | { 280 | foo++; 281 | if ( argc < MAXARGS ) 282 | { 283 | argv[argc++] = foo; 284 | } 285 | while ( !EOS(*foo) && *foo != mQuoteChar ) foo++; 286 | if ( !EOS(*foo) ) 287 | { 288 | *foo = 0; // replace close quote with zero byte EOS 289 | foo++; 290 | } 291 | } 292 | else 293 | { 294 | 295 | foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces 296 | 297 | if ( IsNonSeparator(*foo) ) // add non-hard argument. 298 | { 299 | bool quote = false; 300 | if ( *foo == mQuoteChar ) 301 | { 302 | foo++; 303 | quote = true; 304 | } 305 | 306 | if ( argc < MAXARGS ) 307 | { 308 | argv[argc++] = foo; 309 | } 310 | 311 | if ( quote ) 312 | { 313 | while (*foo && *foo != mQuoteChar ) foo++; 314 | if ( *foo ) *foo = 32; 315 | } 316 | 317 | // continue..until we hit an eos .. 318 | while ( !EOS(*foo) ) // until we hit EOS 319 | { 320 | if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit 321 | { 322 | *foo = 0; 323 | foo++; 324 | break; 325 | } 326 | else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument 327 | { 328 | const char *hard = &mHardString[*foo*2]; 329 | *foo = 0; 330 | if ( argc < MAXARGS ) 331 | { 332 | argv[argc++] = hard; 333 | } 334 | foo++; 335 | break; 336 | } 337 | foo++; 338 | } // end of while loop... 339 | } 340 | } 341 | } 342 | 343 | if ( argc ) 344 | { 345 | ret = callback->ParseLine(lineno, argc, argv ); 346 | } 347 | 348 | return ret; 349 | } 350 | 351 | int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason 352 | { 353 | assert( callback ); 354 | if ( !mData ) return 0; 355 | 356 | int ret = 0; 357 | 358 | int lineno = 0; 359 | 360 | char *foo = mData; 361 | char *begin = foo; 362 | 363 | 364 | while ( *foo ) 365 | { 366 | if ( *foo == 10 || *foo == 13 ) 367 | { 368 | lineno++; 369 | *foo = 0; 370 | 371 | if ( *begin ) // if there is any data to parse at all... 372 | { 373 | int v = ProcessLine(lineno,begin,callback); 374 | if ( v ) ret = v; 375 | } 376 | 377 | foo++; 378 | if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format... 379 | begin = foo; 380 | } 381 | else 382 | { 383 | foo++; 384 | } 385 | } 386 | 387 | lineno++; // lasst line. 388 | 389 | int v = ProcessLine(lineno,begin,callback); 390 | if ( v ) ret = v; 391 | return ret; 392 | } 393 | 394 | 395 | void InPlaceParser::DefaultSymbols(void) 396 | { 397 | SetHardSeparator(','); 398 | SetHardSeparator('('); 399 | SetHardSeparator(')'); 400 | SetHardSeparator('='); 401 | SetHardSeparator('['); 402 | SetHardSeparator(']'); 403 | SetHardSeparator('{'); 404 | SetHardSeparator('}'); 405 | SetCommentSymbol('#'); 406 | } 407 | 408 | 409 | const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse. 410 | { 411 | const char **ret = 0; 412 | 413 | static const char *argv[MAXARGS]; 414 | int argc = 0; 415 | 416 | char *foo = line; 417 | 418 | while ( !EOS(*foo) && argc < MAXARGS ) 419 | { 420 | 421 | foo = SkipSpaces(foo); // skip any leading spaces 422 | 423 | if ( EOS(*foo) ) break; 424 | 425 | if ( *foo == mQuoteChar ) // if it is an open quote 426 | { 427 | foo++; 428 | if ( argc < MAXARGS ) 429 | { 430 | argv[argc++] = foo; 431 | } 432 | while ( !EOS(*foo) && *foo != mQuoteChar ) foo++; 433 | if ( !EOS(*foo) ) 434 | { 435 | *foo = 0; // replace close quote with zero byte EOS 436 | foo++; 437 | } 438 | } 439 | else 440 | { 441 | 442 | foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces 443 | 444 | if ( IsNonSeparator(*foo) ) // add non-hard argument. 445 | { 446 | bool quote = false; 447 | if ( *foo == mQuoteChar ) 448 | { 449 | foo++; 450 | quote = true; 451 | } 452 | 453 | if ( argc < MAXARGS ) 454 | { 455 | argv[argc++] = foo; 456 | } 457 | 458 | if ( quote ) 459 | { 460 | while (*foo && *foo != mQuoteChar ) foo++; 461 | if ( *foo ) *foo = 32; 462 | } 463 | 464 | // continue..until we hit an eos .. 465 | while ( !EOS(*foo) ) // until we hit EOS 466 | { 467 | if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit 468 | { 469 | *foo = 0; 470 | foo++; 471 | break; 472 | } 473 | else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument 474 | { 475 | const char *hard = &mHardString[*foo*2]; 476 | *foo = 0; 477 | if ( argc < MAXARGS ) 478 | { 479 | argv[argc++] = hard; 480 | } 481 | foo++; 482 | break; 483 | } 484 | foo++; 485 | } // end of while loop... 486 | } 487 | } 488 | } 489 | 490 | count = argc; 491 | if ( argc ) 492 | { 493 | ret = argv; 494 | } 495 | 496 | return ret; 497 | } 498 | 499 | /*******************************************************************/ 500 | /******************** Geometry.h ********************************/ 501 | /*******************************************************************/ 502 | 503 | class GeometryVertex 504 | { 505 | public: 506 | float mPos[3]; 507 | float mNormal[3]; 508 | float mTexel[2]; 509 | }; 510 | 511 | 512 | class GeometryInterface 513 | { 514 | public: 515 | 516 | virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3) 517 | { 518 | } 519 | 520 | }; 521 | 522 | 523 | /*******************************************************************/ 524 | /******************** Obj.h ********************************/ 525 | /*******************************************************************/ 526 | 527 | 528 | class OBJ : public InPlaceParserInterface 529 | { 530 | public: 531 | int LoadMesh(const char *fname,GeometryInterface *callback); 532 | int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process 533 | private: 534 | 535 | void GetVertex(GeometryVertex &v,const char *face) const; 536 | 537 | FloatVector mVerts; 538 | FloatVector mTexels; 539 | FloatVector mNormals; 540 | 541 | GeometryInterface *mCallback; 542 | }; 543 | 544 | 545 | /*******************************************************************/ 546 | /******************** Obj.cpp ********************************/ 547 | /*******************************************************************/ 548 | 549 | int OBJ::LoadMesh(const char *fname,GeometryInterface *iface) 550 | { 551 | int ret = 0; 552 | 553 | mVerts.clear(); 554 | mTexels.clear(); 555 | mNormals.clear(); 556 | 557 | mCallback = iface; 558 | 559 | InPlaceParser ipp(fname); 560 | 561 | ipp.Parse(this); 562 | 563 | 564 | return ret; 565 | } 566 | 567 | static const char * GetArg(const char **argv,int i,int argc) 568 | { 569 | const char * ret = 0; 570 | if ( i < argc ) ret = argv[i]; 571 | return ret; 572 | } 573 | 574 | void OBJ::GetVertex(GeometryVertex &v,const char *face) const 575 | { 576 | v.mPos[0] = 0; 577 | v.mPos[1] = 0; 578 | v.mPos[2] = 0; 579 | 580 | v.mTexel[0] = 0; 581 | v.mTexel[1] = 0; 582 | 583 | v.mNormal[0] = 0; 584 | v.mNormal[1] = 1; 585 | v.mNormal[2] = 0; 586 | 587 | int index = atoi( face )-1; 588 | 589 | const char *texel = strstr(face,"/"); 590 | 591 | if ( texel ) 592 | { 593 | int tindex = atoi( texel+1) - 1; 594 | 595 | if ( tindex >=0 && tindex < (int)(mTexels.size()/2) ) 596 | { 597 | const float *t = &mTexels[tindex*2]; 598 | 599 | v.mTexel[0] = t[0]; 600 | v.mTexel[1] = t[1]; 601 | 602 | } 603 | 604 | const char *normal = strstr(texel+1,"/"); 605 | if ( normal ) 606 | { 607 | int nindex = atoi( normal+1 ) - 1; 608 | 609 | if (nindex >= 0 && nindex < (int)(mNormals.size()/3) ) 610 | { 611 | const float *n = &mNormals[nindex*3]; 612 | 613 | v.mNormal[0] = n[0]; 614 | v.mNormal[1] = n[1]; 615 | v.mNormal[2] = n[2]; 616 | } 617 | } 618 | } 619 | 620 | if ( index >= 0 && index < (int)(mVerts.size()/3) ) 621 | { 622 | 623 | const float *p = &mVerts[index*3]; 624 | 625 | v.mPos[0] = p[0]; 626 | v.mPos[1] = p[1]; 627 | v.mPos[2] = p[2]; 628 | } 629 | 630 | } 631 | 632 | int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process 633 | { 634 | int ret = 0; 635 | 636 | if ( argc >= 1 ) 637 | { 638 | const char *foo = argv[0]; 639 | if ( *foo != '#' ) 640 | { 641 | if ( stricmp(argv[0],"v") == 0 && argc == 4 ) 642 | { 643 | float vx = (float) atof( argv[1] ); 644 | float vy = (float) atof( argv[2] ); 645 | float vz = (float) atof( argv[3] ); 646 | mVerts.push_back(vx); 647 | mVerts.push_back(vy); 648 | mVerts.push_back(vz); 649 | } 650 | else if ( stricmp(argv[0],"vt") == 0 && argc == 3 ) 651 | { 652 | float tx = (float) atof( argv[1] ); 653 | float ty = (float) atof( argv[2] ); 654 | mTexels.push_back(tx); 655 | mTexels.push_back(ty); 656 | } 657 | else if ( stricmp(argv[0],"vn") == 0 && argc == 4 ) 658 | { 659 | float normalx = (float) atof(argv[1]); 660 | float normaly = (float) atof(argv[2]); 661 | float normalz = (float) atof(argv[3]); 662 | mNormals.push_back(normalx); 663 | mNormals.push_back(normaly); 664 | mNormals.push_back(normalz); 665 | } 666 | else if ( stricmp(argv[0],"f") == 0 && argc >= 4 ) 667 | { 668 | GeometryVertex v[32]; 669 | 670 | int vcount = argc-1; 671 | 672 | for (int i=1; i p1( v[0].mPos ); 682 | Vector3d p2( v[1].mPos ); 683 | Vector3d p3( v[2].mPos ); 684 | 685 | Vector3d n; 686 | n.ComputeNormal(p3,p2,p1); 687 | 688 | for (int i=0; iNodeTriangle(&v[0],&v[1],&v[2]); 699 | 700 | if ( vcount >=3 ) // do the fan 701 | { 702 | for (int i=2; i<(vcount-1); i++) 703 | { 704 | mCallback->NodeTriangle(&v[0],&v[i],&v[i+1]); 705 | } 706 | } 707 | 708 | } 709 | } 710 | } 711 | 712 | return ret; 713 | } 714 | 715 | 716 | 717 | 718 | class BuildMesh : public GeometryInterface 719 | { 720 | public: 721 | 722 | int GetIndex(const float *p) 723 | { 724 | 725 | int vcount = mVertices.size()/3; 726 | 727 | if(vcount>0) 728 | { 729 | //New MS STL library checks indices in debug build, so zero causes an assert if it is empty. 730 | const float *v = &mVertices[0]; 731 | 732 | for (int i=0; imPos) ); 749 | mIndices.push_back( GetIndex(v2->mPos) ); 750 | mIndices.push_back( GetIndex(v3->mPos) ); 751 | } 752 | 753 | const FloatVector& GetVertices(void) const { return mVertices; }; 754 | const IntVector& GetIndices(void) const { return mIndices; }; 755 | 756 | private: 757 | FloatVector mVertices; 758 | IntVector mIndices; 759 | }; 760 | 761 | }; 762 | 763 | using namespace WAVEFRONT; 764 | 765 | WavefrontObj::WavefrontObj(void) 766 | { 767 | mVertexCount = 0; 768 | mTriCount = 0; 769 | mIndices = 0; 770 | mVertices = 0; 771 | } 772 | 773 | WavefrontObj::~WavefrontObj(void) 774 | { 775 | delete mIndices; 776 | delete mVertices; 777 | } 778 | 779 | unsigned int WavefrontObj::loadObj(const char *fname) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed. 780 | { 781 | 782 | unsigned int ret = 0; 783 | 784 | delete mVertices; 785 | mVertices = 0; 786 | delete mIndices; 787 | mIndices = 0; 788 | mVertexCount = 0; 789 | mTriCount = 0; 790 | 791 | 792 | BuildMesh bm; 793 | 794 | OBJ obj; 795 | 796 | obj.LoadMesh(fname,&bm); 797 | 798 | 799 | const FloatVector &vlist = bm.GetVertices(); 800 | const IntVector &indices = bm.GetIndices(); 801 | if ( vlist.size() ) 802 | { 803 | mVertexCount = vlist.size()/3; 804 | mVertices = new float[mVertexCount*3]; 805 | memcpy( mVertices, &vlist[0], sizeof(float)*mVertexCount*3 ); 806 | mTriCount = indices.size()/3; 807 | mIndices = new int[mTriCount*3*sizeof(int)]; 808 | memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3); 809 | ret = mTriCount; 810 | } 811 | 812 | 813 | return ret; 814 | } 815 | 816 | -------------------------------------------------------------------------------- /StanHull/wavefront.h: -------------------------------------------------------------------------------- 1 | #ifndef WAVEFRONT_OBJ_H 2 | 3 | 4 | #define WAVEFRONT_OBJ_H 5 | 6 | /*---------------------------------------------------------------------- 7 | Copyright (c) 2004 Open Dynamics Framework Group 8 | www.physicstools.org 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 12 | that the following conditions are met: 13 | 14 | Redistributions of source code must retain the above copyright notice, this list of conditions 15 | and the following disclaimer. 16 | 17 | Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | Neither the name of the Open Dynamics Framework Group nor the names of its contributors may 22 | be used to endorse or promote products derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, 25 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -----------------------------------------------------------------------*/ 32 | 33 | class WavefrontObj 34 | { 35 | public: 36 | 37 | WavefrontObj(void); 38 | ~WavefrontObj(void); 39 | 40 | unsigned int loadObj(const char *fname); // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed. 41 | 42 | int mVertexCount; 43 | int mTriCount; 44 | int *mIndices; 45 | float *mVertices; 46 | }; 47 | 48 | #endif 49 | --------------------------------------------------------------------------------