├── .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 |
--------------------------------------------------------------------------------