├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── modules │ ├── FindMaya.cmake │ └── version.cmake ├── docs └── images │ ├── OsbSanityFourSidedPolies.png │ ├── OsbSanityGRPGEO.png │ ├── OsbSanityInherit.png │ ├── OsbSanityModularity.png │ ├── OsbSanityNodeEndings.png │ ├── OsbSanityNonManifold.png │ ├── OsbSanityNormalDirection.png │ ├── OsbSanityNumberPadding.png │ ├── OsbSanityOpenFaces.png │ ├── OsbSanityPadding.png │ ├── OsbSanityReversedUVs.png │ ├── OsbSanityRunOnAllGeo.png │ ├── OsbSanitySplitBorders.png │ ├── OsbSanityTopGroupPivot.png │ ├── OsbSanityUVOverlap.png │ ├── OsbSanityUVOverlappingTileBorder.png │ ├── OsbSanityUVSeams.png │ ├── OsbSanityUVsInRightQuarter.png │ ├── OsbSanityVallence.png │ ├── OsbSanityZeroLengthEdge.png │ └── SanityChecker.png ├── mel ├── checks │ ├── geo │ │ ├── osbSanity11EdgesAtOnePoint.mel │ │ ├── osbSanityBorders.mel │ │ ├── osbSanityDeleteHistory.mel │ │ ├── osbSanityDeleteLayersAndDagNodes.mel │ │ ├── osbSanityDeleteShadersApplyLambert.mel │ │ ├── osbSanityHolesBorder.mel │ │ ├── osbSanityLaminaFaces.mel │ │ ├── osbSanityMoreThanFourEdges.mel │ │ ├── osbSanityNonManifoldFaces.mel │ │ ├── osbSanityNormals.mel │ │ ├── osbSanityWarnRefMaterial.mel │ │ └── osbSanityZeroLengthEdges.mel │ ├── naming │ │ ├── osbSanityNameClashes.mel │ │ ├── osbSanityNameEndings.mel │ │ └── osbSanityNumberPadding.mel │ ├── transform │ │ ├── osbSanityFreezTransforms.mel │ │ ├── osbSanityGeoAtZero.mel │ │ └── osbSanityTopGroupNodeToZero.mel │ └── uv │ │ ├── osbSanityUVBorders.mel │ │ ├── osbSanityUVOverlapping.mel │ │ ├── osbSanityUVShellsOverlapping.mel │ │ ├── osbSanityUVsInRightGrid.mel │ │ └── osbSanityUVsReversed.mel ├── cleanUpScene.mel ├── osbSanityChecker.mel ├── osbSanityCheckerAPI.mel └── osbUserChecks.mel ├── osbTools.mod.in ├── py ├── InheritParentsName.py ├── NewtonRenaming.py └── ResolveDuplicates.py ├── src ├── CMakeLists.txt ├── Renaming.cpp ├── Renaming.h ├── UVCommon.cpp ├── UVCommon.h ├── UVReversed.cpp ├── UVReversed.h ├── UVSeams.cpp ├── UVSeams.h ├── holesBorder.cpp ├── holesBorder.h ├── intersect.cpp ├── intersect.h ├── overlappingUVShells.cpp ├── overlappingUVShells.h ├── pluginMain.cpp └── triangleOverlappingTest.cpp ├── ui ├── osbSanityCheckHelp.py ├── osbSanityCheckHelp_UI.py └── osbSanityCheckHelp_UI.ui └── windows ├── newton.sln ├── newton.sln.old └── newton.vcproj /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | 3 | # Compiled Object files 4 | *.slo 5 | *.lo 6 | *.o 7 | 8 | # Compiled Dynamic libraries 9 | *.so 10 | *.dylib 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(osbTools) 3 | 4 | #set(PROJECT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT}) 5 | #set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install) 6 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) 7 | 8 | # Get the current version 9 | include(version) 10 | 11 | add_definitions( 12 | -DOSBTOOLS_MAJOR_VERSION="${OSBTOOLS_MAJOR_VERSION}" 13 | -DOSBTOOLS_MINOR_VERSION="${OSBTOOLS_MINOR_VERSION}" 14 | -DOSBTOOLS_PATCH_VERSION="${OSBTOOLS_PATCH_VERSION}") 15 | 16 | set(LINUX FALSE) 17 | if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") 18 | set(LINUX TRUE) 19 | endif() 20 | 21 | if (LINUX) 22 | include(CheckCXXCompilerFlag) 23 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 24 | CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) 25 | if (COMPILER_SUPPORTS_CXX11) 26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 27 | elseif (COMPILER_SUPPORTS_CXX0X) 28 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") 29 | endif() 30 | endif() 31 | 32 | 33 | # Set some debug vs opt flags 34 | if ("${CMAKE_BUILD_TYPE}" MATCHES "Debug") 35 | add_definitions(-DDEBUG=1 -UNDEBUG) 36 | if (LINUX) 37 | add_definitions( 38 | -Wall 39 | -Wextra 40 | -Wno-deprecated-register 41 | -Wno-ignored-qualifiers 42 | -Wno-reorder 43 | -Wno-unused-local-typedefs 44 | -Wno-unused-parameter) 45 | endif() 46 | elseif ("${CMAKE_BUILD_TYPE}" MATCHES "Release") 47 | add_definitions(-DNDEBUG=1 -UDEBUG) 48 | if (LINUX) 49 | add_definitions(-O3 -Wno-deprecated-register) 50 | endif() 51 | endif() 52 | 53 | 54 | add_subdirectory(src) 55 | 56 | #configure_file("${CMAKE_CURRENT_SOURCE_DIR}/module.txt" "${PROJECT_PATH}/${PROJECT_NAME}.txt") 57 | 58 | configure_file ( 59 | "${CMAKE_CURRENT_SOURCE_DIR}/osbTools.mod.in" 60 | "${CMAKE_BINARY_DIR}/osbTools.mod") 61 | 62 | install(DIRECTORY mel/ DESTINATION scripts) 63 | install(FILES py/InheritParentsName.py DESTINATION plug-ins) 64 | install(FILES py/ResolveDuplicates.py DESTINATION plug-ins) 65 | install(DIRECTORY ui/ DESTINATION python) 66 | install(FILES py/NewtonRenaming.py DESTINATION python) 67 | #install(FILES osbTools.mod DESTINATION .) 68 | install(FILES "${CMAKE_BINARY_DIR}/osbTools.mod" DESTINATION ${CMAKE_INSTALL_PREFIX}) 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Shyal 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | The Sanity Checking Tool performs sanity checks at the modeling phase. It acts as a user interface, is very easily extensible (see Adding User Checks) and can be called programmatically through other tools (such as publishing tools) to automatically check the sanity of assets before publish. 4 | 5 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/SanityChecker.png) 6 | 7 | #### Dependencies 8 | 9 | osbTools contains MEL, Python and C++. It is also dependent on boost 1.47.0. 10 | 11 | #### Invoking 12 | 13 | From Maya command line: 14 | 15 | ``` 16 | source "osbSanityChecker.mel"; 17 | ``` 18 | 19 | #### Check types 20 | 21 | There are various types of checks: 22 | 23 | * Perform: This is a one step check which performs its duties in a single click. 24 | 25 | * Check, Select: This type of check is for information purposes only, it will detect a defect in the and enable the user to select the problematic components. 26 | 27 | * Check, Select, Fix: This is a 3 step check which enables the user to run a test, select the problematic components, and fix them. 28 | 29 | #### Scope 30 | 31 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityRunOnAllGeo.png) 32 | 33 | When '''edit > Run on all geo''' is checked, the checks will be run on the whole scene. When it is unchecked the checks will run on the selected geometry only. 34 | 35 | #### Modularity 36 | 37 | Ticking the check-boxes to the left of the checks, then click '''edit > hide checked items''' will hide selected items from the window. This enables to only work with UV tests for example. This combined with the ability to add your own checks means users can use this as a framework to add their own checks and make the tool their own. 38 | 39 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityModularity.png) 40 | 41 | To unhide hidden checks, simply click '''edit > reset'''. 42 | 43 | ## Geo Checks 44 | 45 | ### Open edges / Border edge ### 46 | 47 | This check looks for open borders in polygon shells and the fix closes them. This is a default Maya test. 48 | 49 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityOpenFaces.png) 50 | 51 | ### Add borders to holes 52 | 53 | This check looks for open borders in polygon shells and adds an edge loop to their border. 54 | 55 | 56 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanitySplitBorders.png) 57 | 58 | 59 | ### Floating vertex/zero edge length 60 | 61 | This checks for edges whose two vertices are less than 1e-05 units apart. 62 | 63 | 64 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityZeroLengthEdge.png) 65 | 66 | 67 | ### No more than four sided polys 68 | 69 | Makes sure that no polygonal faces have more than 4 edges. The Fix is performed by triangulating offending faces. This is a default maya test. 70 | 71 | 72 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityFourSidedPolies.png) 73 | 74 | 75 | ### No non maniforld faces 76 | 77 | Fixes non-manifold geometry, this is default maya functionality. For more information on non-manifold geometry please refer to the [ 78 | maya doc](http://download.autodesk.com/global/docs/maya2013/en_us/index.html?url=files/Polygons_overview_Twomanifold_vs._nonmanifold_polygonal_geometry.htm,topicNumber=d30e132600). 79 | 80 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityNonManifold.png) 81 | 82 | ### No lamina faces 83 | 84 | This is a default maya test. From the maya documentation: 85 | 86 | "Lamina faces share all of their edges. When you select Lamina Faces for removal, Maya removes faces that share all edges. By removing these types of faces, you can avoid unnecessary processing time, especially when you export the model to a game console. For example, suppose you performed Edit Mesh > Duplicate Face with the Separate Duplicate Faces option turned off. You would have two faces on top of each other. If you later merge the vertices of the two faces, they would share the same edges. You can remove the extra face using Cleanup with Lamina faces turned on." 87 | 88 | ### Delete shaders assign lambert1 shader 89 | 90 | This check deletes all shaders in the scene and applies the default lambert material to all polygonal geometry 91 | 92 | ### Give warning if reference geo is in the scene 93 | 94 | This checks whether there are any maya references left in the scene. 95 | 96 | ### Vallence check: No more than 11 edges going into one point 97 | 98 | his check makes sure there are no more than 11 edges meeting atone single vertex.If there are more then the fix will remove every second edge. 99 | 100 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityVallence.png) 101 | 102 | ### Check polygon normals facing the right direction 103 | 104 | This checks whether the normals for the object are facing 'outwards'. It uses a combination of two statistical methods to do so, and selects the method with the highest level of confidence. Please note that this check assumes that normals are conformed before running. 105 | 106 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityNormalDirection.png) 107 | 108 | ### Delete all history 109 | 110 | This check deletes history on all nodes. 111 | 112 | ## Transform Checks 113 | 114 | ### Freeze transforms 115 | 116 | This check freezes all transform nodes in the scene. 117 | 118 | ### Place top group node pivot to world 0 119 | 120 | This places the top level group node's pivot at world (0,0,0). This check will not work if there is more than 1 top group transform. 121 | 122 | 123 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityTopGroupPivot.png) 124 | 125 | 126 | ### no geo below -0.005 in Y 127 | 128 | This check ensures that no geometry's bounding box is below -0.005 129 | 130 | ## Naming Conventions 131 | 132 | ### Check that all geo and group nodes have a number padding 133 | 134 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityNumberPadding.png) 135 | 136 | 137 | This dialog offers renaming features for the entire hierarchy or for selection. 138 | 139 | #### Inherit Parent's Name 140 | 141 | [[File:osbSanityInherit.png]] 142 | 143 | This feature simply renames geometry to its immediate parents' name. 144 | 145 | 146 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityPadding.png) 147 | 148 | This feature is a little more complex, first of all it makes sure that every geometry name in the scene is unique. This is useful as a lot of maya scripts fail when there are more than one object having the same name. It also numbers each piece of geometry according to its position within the hierarchy. 149 | 150 | ### Check that all geo and group nodes end in _GEO/_PLY/_GRP 151 | 152 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityNodeEndings.png) 153 | 154 | Checking '''_GRP''' will add the '_GRP' suffix to the end of all groups. 155 | 156 | Checking '''_PLY''' or '''_GEO''' will add either of those suffixes at the end of geo nodes. However it will only do so on geo nodes which don't currently have a suffix. If you want to override the existing suffix you'll have to first tick '''force _PLY|_GEO'''. 157 | 158 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityGRPGEO.png) 159 | 160 | ## UV Checking 161 | 162 | ### Check there are no open UV seams 163 | 164 | 165 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityUVSeams.png) 166 | 167 | This check detects seams (cuts) in UVs which are not otherwise visible. For example if you select edges on a model and use the scissors tool to cut them, this is a perfect example of a seam which this check will detect. 168 | 169 | ### Check no UV edges are overlapping a tile border 170 | 171 | Check that no UVs are overlapping a tile border. This is important as all the UVs per object need to fit within one grid tile. 172 | 173 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityUVOverlappingTileBorder.png) 174 | 175 | ### Check no UV edges are overlapping each other 176 | 177 | Check no UVs/UV shells are overlapping each other. UV Shells should not overlap since they'll inherit the same texture pixels if they do. This check makes sure no shells within the same object overlap. 178 | 179 | '''n.b.''' this check seems to currently be broken. 180 | 181 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityUVOverlap.png) 182 | 183 | ### Check no UVs are reversed/inverted (like poly normals 184 | 185 | This checks that no UVs are facing down, to make sure textures don't show up inverted. 186 | 187 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityReversedUVs.png) 188 | 189 | ### (Check no UVs are in -1 tiles in Y and X 190 | 191 | Make sure UVs are only in the positive areas of the UV grid. 192 | 193 | ![](https://raw.githubusercontent.com/shyal/osbTools/master/docs/images/OsbSanityUVsInRightQuarter.png) 194 | 195 | ## Scene Check 196 | ### Delete layers/unimportant DAG nodes 197 | 198 | This check deletes the defaultLightSet, the defaultObjectSet, displayLayers, defaultLayers, defaultRenderLayers, brushs ikRPsolvers, ikSCsolvers, ikSplineSolvers, DisplayLayers and RenderLayers 199 | 200 | ## Adding User Checks 201 | 202 | The sanity checker is a simple API allowing you to easily add your own checks. 203 | 204 | You can either put your own checks in osbUserChecks.mel directly, or put them in seperate mel files and source those files from osbUserChecks.mel 205 | 206 | Your checks should start with: 207 | 208 | ``` 209 | source "osbSanityCheckerAPI.mel"; 210 | ``` 211 | 212 | 213 | The registration command is: 214 | 215 | ``` 216 | osbAddSanityCheck("exampleCheckName", 217 | "Example Category Name", 218 | "Example label - this name appears in the UI", 219 | "Example Tooltip - this help shows up when hovering over the check in the UI", 220 | "Perform"); 221 | ``` 222 | 223 | The last string can either be "Perform" or "Perform,Select,fix". A "Perform" check will do all that is required in one function. For this check you'll need to declare and define a global function that has the same name as the first argument, so: 224 | 225 | ``` 226 | global proc exampleCheckName() 227 | { 228 | // checking code here 229 | } 230 | ``` 231 | 232 | The function signature contains no arguments and the function has no return value. Within the function, you can assume that the correct objects that you want to check are currently selected. 233 | 234 | The second kind of check is "Perform,Select,fix". For this type of check, the objects / components which remain selected when exampleCheckName() returns are the objects that will get added to the selection set which flags them as being problematic. 235 | 236 | ``` 237 | global proc exampleCheckNameFix() 238 | { 239 | // fixing code here 240 | } 241 | ``` 242 | 243 | Once again, in this function, you can assume that the problematic objects / components that you want to fix are currently selected. 244 | 245 | Your best option to get up to running is to take a look at existing checks inside the 'checks' directory. 246 | 247 | If the checks that you add are used a lot please feel free to add them to the main tool and check your changes into the newton repos in bitbucket. Please also note that existing checks can be hidding by using edit > Hide selected checks, go ahead and hide checks that you do not use, and implement your own checks to make this tool your own. 248 | -------------------------------------------------------------------------------- /cmake/modules/FindMaya.cmake: -------------------------------------------------------------------------------- 1 | # - Maya finder module 2 | # This module searches for a valid Maya instalation. 3 | # It searches for Maya's devkit, libraries, executables 4 | # and related paths (scripts) 5 | # 6 | # Variables that will be defined: 7 | # MAYA_FOUND Defined if a Maya installation has been detected 8 | # MAYA_EXECUTABLE Path to Maya's executable 9 | # MAYA__FOUND Defined if has been found 10 | # MAYA__LIBRARY Path to library 11 | # MAYA_INCLUDE_DIRS Path to the devkit's include directories 12 | # MAYA_API_VERSION Maya version (6 digits) 13 | # 14 | # IMPORTANT: Currently, there's only support for OSX platform and Maya version 2017 because of ABI issues with libc++. 15 | 16 | #============================================================================= 17 | # Copyright 2011-2012 Francisco Requena 18 | # 19 | # Distributed under the OSI-approved BSD License (the "License"); 20 | # see accompanying file Copyright.txt for details. 21 | # 22 | # This software is distributed WITHOUT ANY WARRANTY; without even the 23 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 24 | # See the License for more information. 25 | #============================================================================= 26 | # (To distribute this file outside of CMake, substitute the full 27 | # License text for the above reference.) 28 | 29 | if(APPLE) 30 | find_path(MAYA_BASE_DIR 31 | ../../devkit/include/maya/MFn.h 32 | HINTS 33 | "${MAYA_LOCATION}" 34 | "$ENV{MAYA_LOCATION}" 35 | "/Applications/Autodesk/maya2018/Maya.app/Contents" 36 | "/Applications/Autodesk/maya2017/Maya.app/Contents" 37 | "/Applications/Autodesk/maya2016.5/Maya.app/Contents" 38 | "/Applications/Autodesk/maya2016/Maya.app/Contents" 39 | "/Applications/Autodesk/maya2015/Maya.app/Contents" 40 | "/Applications/Autodesk/maya2014/Maya.app/Contents" 41 | "/Applications/Autodesk/maya2013.5/Maya.app/Contents" 42 | "/Applications/Autodesk/maya2013/Maya.app/Contents" 43 | "/Applications/Autodesk/maya2012.17/Maya.app/Contents" 44 | "/Applications/Autodesk/maya2012/Maya.app/Contents" 45 | "/Applications/Autodesk/maya2011/Maya.app/Contents" 46 | "/Applications/Autodesk/maya2010/Maya.app/Contents" 47 | ) 48 | find_path(MAYA_LIBRARY_DIR libOpenMaya.dylib 49 | HINTS 50 | "${MAYA_LOCATION}" 51 | "$ENV{MAYA_LOCATION}" 52 | "${MAYA_BASE_DIR}" 53 | PATH_SUFFIXES 54 | Maya.app/contents/MacOS/ 55 | DOC 56 | "Maya's libraries path" 57 | ) 58 | elseif(UNIX) 59 | find_path(MAYA_BASE_DIR 60 | include/maya/MFn.h 61 | HINTS 62 | "${MAYA_LOCATION}" 63 | "$ENV{MAYA_LOCATION}" 64 | "/usr/autodesk/maya2018" 65 | "/usr/autodesk/maya2017" 66 | "/usr/autodesk/maya2016.5" 67 | "/usr/autodesk/maya2016" 68 | "/usr/autodesk/maya2015-x64" 69 | "/usr/autodesk/maya2014-x64" 70 | "/usr/autodesk/maya2013-x64" 71 | "/usr/autodesk/maya2012.17-x64" 72 | "/usr/autodesk/maya2012-x64" 73 | "/usr/autodesk/maya2011-x64" 74 | "/usr/autodesk/maya2010-x64" 75 | ) 76 | find_path(MAYA_LIBRARY_DIR 77 | libOpenMaya.so 78 | HINTS 79 | "${MAYA_LOCATION}" 80 | "$ENV{MAYA_LOCATION}" 81 | "${MAYA_BASE_DIR}" 82 | PATH_SUFFIXES 83 | lib/ 84 | DOC 85 | "Maya's libraries path" 86 | ) 87 | elseif(WIN32) 88 | find_path(MAYA_BASE_DIR 89 | include/maya/MFn.h 90 | HINTS 91 | "${MAYA_LOCATION}" 92 | "$ENV{MAYA_LOCATION}" 93 | "C:/Program Files/Autodesk/Maya2018" 94 | "C:/Program Files/Autodesk/Maya2017" 95 | "C:/Program Files/Autodesk/Maya2016.5" 96 | "C:/Program Files/Autodesk/Maya2016" 97 | "C:/Program Files/Autodesk/Maya2015.5-x64" 98 | "C:/Program Files/Autodesk/Maya2015.5" 99 | "C:/Program Files/Autodesk/Maya2014.5-x64" 100 | "C:/Program Files/Autodesk/Maya2014.5" 101 | "C:/Program Files/Autodesk/Maya2013.5-x64" 102 | "C:/Program Files/Autodesk/Maya2013.5" 103 | "C:/Program Files (x86)/Autodesk/Maya2013.5" 104 | "C:/Autodesk/maya-2013.5x64" 105 | "C:/Program Files/Autodesk/Maya2013-x64" 106 | "C:/Program Files/Autodesk/Maya2013" 107 | "C:/Program Files (x86)/Autodesk/Maya2013" 108 | "C:/Autodesk/maya-2013x64" 109 | "C:/Program Files/Autodesk/Maya2012-x64" 110 | "C:/Program Files/Autodesk/Maya2012" 111 | "C:/Program Files (x86)/Autodesk/Maya2012" 112 | "C:/Autodesk/maya-2012x64" 113 | "C:/Program Files/Autodesk/Maya2011-x64" 114 | "C:/Program Files/Autodesk/Maya2011" 115 | "C:/Program Files (x86)/Autodesk/Maya2011" 116 | "C:/Autodesk/maya-2011x64" 117 | "C:/Program Files/Autodesk/Maya2010-x64" 118 | "C:/Program Files/Autodesk/Maya2010" 119 | "C:/Program Files (x86)/Autodesk/Maya2010" 120 | "C:/Autodesk/maya-2010x64" 121 | ) 122 | find_path(MAYA_LIBRARY_DIR 123 | OpenMaya.lib 124 | HINTS 125 | "${MAYA_LOCATION}" 126 | "$ENV{MAYA_LOCATION}" 127 | "${MAYA_BASE_DIR}" 128 | PATH_SUFFIXES 129 | lib/ 130 | DOC 131 | "Maya's libraries path" 132 | ) 133 | endif() 134 | 135 | find_path(MAYA_INCLUDE_DIR 136 | maya/MFn.h 137 | HINTS 138 | "${MAYA_LOCATION}" 139 | "$ENV{MAYA_LOCATION}" 140 | "${MAYA_BASE_DIR}" 141 | PATH_SUFFIXES 142 | ../../devkit/include/ 143 | include/ 144 | DOC 145 | "Maya's devkit headers path" 146 | ) 147 | 148 | find_path(MAYA_LIBRARY_DIR 149 | OpenMaya 150 | HINTS 151 | "${MAYA_LOCATION}" 152 | "$ENV{MAYA_LOCATION}" 153 | "${MAYA_BASE_DIR}" 154 | PATH_SUFFIXES 155 | ../../devkit/include/ 156 | include/ 157 | DOC 158 | "Maya's devkit headers path" 159 | ) 160 | 161 | list(APPEND MAYA_INCLUDE_DIRS ${MAYA_INCLUDE_DIR}) 162 | 163 | find_path(MAYA_DEVKIT_INC_DIR 164 | GL/glext.h 165 | HINTS 166 | "${MAYA_LOCATION}" 167 | "$ENV{MAYA_LOCATION}" 168 | "${MAYA_BASE_DIR}" 169 | PATH_SUFFIXES 170 | ../../devkit/plug-ins/ 171 | DOC 172 | "Maya's devkit headers path" 173 | ) 174 | if(NOT "${MAYA_DEVKIT_INC_DIR}" STREQUAL "MAYA_DEVKIT_INC_DIR-NOTFOUND") 175 | list(APPEND MAYA_INCLUDE_DIRS ${MAYA_DEVKIT_INC_DIR}) 176 | endif() 177 | 178 | foreach(MAYA_LIB 179 | OpenMaya 180 | OpenMayaAnim 181 | OpenMayaFX 182 | OpenMayaRender 183 | OpenMayaUI 184 | Image 185 | Foundation 186 | IMFbase 187 | tbb 188 | cg 189 | cgGL) 190 | 191 | find_library(MAYA_${MAYA_LIB}_LIBRARY 192 | ${MAYA_LIB} 193 | HINTS 194 | "${MAYA_LOCATION}" 195 | "$ENV{MAYA_LOCATION}" 196 | "${MAYA_BASE_DIR}" 197 | PATH_SUFFIXES 198 | MacOS/ 199 | lib/ 200 | DOC 201 | "Maya's ${MAYA_LIB} library path" 202 | # NO_CMAKE_SYSTEM_PATH needed to avoid conflicts between 203 | # Maya's Foundation library and OSX's framework. 204 | NO_CMAKE_SYSTEM_PATH 205 | ) 206 | 207 | 208 | if (MAYA_${MAYA_LIB}_LIBRARY) 209 | list(APPEND MAYA_LIBRARIES ${MAYA_${MAYA_LIB}_LIBRARY}) 210 | endif() 211 | endforeach(MAYA_LIB) 212 | 213 | find_program(MAYA_EXECUTABLE 214 | maya 215 | HINTS 216 | "${MAYA_LOCATION}" 217 | "$ENV{MAYA_LOCATION}" 218 | "${MAYA_BASE_DIR}" 219 | PATH_SUFFIXES 220 | MacOS/ 221 | bin/ 222 | DOC 223 | "Maya's executable path" 224 | ) 225 | 226 | if(MAYA_INCLUDE_DIRS AND EXISTS "${MAYA_INCLUDE_DIR}/maya/MTypes.h") 227 | 228 | # Tease the MAYA_API_VERSION numbers from the lib headers 229 | file(STRINGS ${MAYA_INCLUDE_DIR}/maya/MTypes.h TMP REGEX "#define MAYA_API_VERSION.*$") 230 | string(REGEX MATCHALL "[0-9]+" MAYA_API_VERSION ${TMP}) 231 | endif() 232 | 233 | # handle the QUIETLY and REQUIRED arguments and set MAYA_FOUND to TRUE if 234 | # all listed variables are TRUE 235 | include(FindPackageHandleStandardArgs) 236 | 237 | find_package_handle_standard_args(Maya 238 | REQUIRED_VARS 239 | MAYA_EXECUTABLE 240 | MAYA_INCLUDE_DIRS 241 | MAYA_LIBRARIES 242 | VERSION_VAR 243 | MAYA_API_VERSION 244 | ) 245 | -------------------------------------------------------------------------------- /cmake/modules/version.cmake: -------------------------------------------------------------------------------- 1 | find_package(Git REQUIRED) 2 | 3 | # Get the current git commit 4 | execute_process( 5 | COMMAND 6 | ${GIT_EXECUTABLE} rev-parse HEAD 7 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 8 | OUTPUT_VARIABLE CURRENT_COMMIT 9 | ERROR_QUIET 10 | OUTPUT_STRIP_TRAILING_WHITESPACE) 11 | 12 | # Get the latest git commit that contains a tag 13 | execute_process( 14 | COMMAND 15 | ${GIT_EXECUTABLE} rev-list --tags --max-count=1 16 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 17 | OUTPUT_VARIABLE LATEST_TAG_COMMIT 18 | ERROR_QUIET 19 | OUTPUT_STRIP_TRAILING_WHITESPACE) 20 | 21 | if(LATEST_TAG_COMMIT) 22 | # Get the latest git tag 23 | execute_process( 24 | COMMAND 25 | ${GIT_EXECUTABLE} describe --tags ${LATEST_TAG_COMMIT} 26 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 27 | OUTPUT_VARIABLE OSBTOOLS_VERSION 28 | ERROR_QUIET 29 | OUTPUT_STRIP_TRAILING_WHITESPACE) 30 | else() 31 | set(OSBTOOLS_VERSION "0.0.0") 32 | message(WARNING "No git tag found, using version ${OSBTOOLS_VERSION}") 33 | endif() 34 | 35 | # Split it with '.' symbol 36 | string(REPLACE "-" ";" VERSION_LIST ${OSBTOOLS_VERSION}) 37 | string(REPLACE "." ";" VERSION_LIST ${VERSION_LIST}) 38 | 39 | # Get the version list 40 | list(GET VERSION_LIST 0 OSBTOOLS_MAJOR_VERSION) 41 | list(GET VERSION_LIST 1 OSBTOOLS_MINOR_VERSION) 42 | list(GET VERSION_LIST 2 OSBTOOLS_PATCH_VERSION) 43 | 44 | # Increase the patch version if current commit is not tagged. 45 | if( NOT "${CURRENT_COMMIT}" MATCHES "${LATEST_TAG_COMMIT}" ) 46 | math(EXPR OSBTOOLS_PATCH_VERSION "${OSBTOOLS_PATCH_VERSION}+1") 47 | endif() 48 | 49 | message( "osbTools version is ${OSBTOOLS_MAJOR_VERSION}.${OSBTOOLS_MINOR_VERSION}.${OSBTOOLS_PATCH_VERSION}" ) 50 | 51 | -------------------------------------------------------------------------------- /docs/images/OsbSanityFourSidedPolies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityFourSidedPolies.png -------------------------------------------------------------------------------- /docs/images/OsbSanityGRPGEO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityGRPGEO.png -------------------------------------------------------------------------------- /docs/images/OsbSanityInherit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityInherit.png -------------------------------------------------------------------------------- /docs/images/OsbSanityModularity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityModularity.png -------------------------------------------------------------------------------- /docs/images/OsbSanityNodeEndings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityNodeEndings.png -------------------------------------------------------------------------------- /docs/images/OsbSanityNonManifold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityNonManifold.png -------------------------------------------------------------------------------- /docs/images/OsbSanityNormalDirection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityNormalDirection.png -------------------------------------------------------------------------------- /docs/images/OsbSanityNumberPadding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityNumberPadding.png -------------------------------------------------------------------------------- /docs/images/OsbSanityOpenFaces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityOpenFaces.png -------------------------------------------------------------------------------- /docs/images/OsbSanityPadding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityPadding.png -------------------------------------------------------------------------------- /docs/images/OsbSanityReversedUVs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityReversedUVs.png -------------------------------------------------------------------------------- /docs/images/OsbSanityRunOnAllGeo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityRunOnAllGeo.png -------------------------------------------------------------------------------- /docs/images/OsbSanitySplitBorders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanitySplitBorders.png -------------------------------------------------------------------------------- /docs/images/OsbSanityTopGroupPivot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityTopGroupPivot.png -------------------------------------------------------------------------------- /docs/images/OsbSanityUVOverlap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityUVOverlap.png -------------------------------------------------------------------------------- /docs/images/OsbSanityUVOverlappingTileBorder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityUVOverlappingTileBorder.png -------------------------------------------------------------------------------- /docs/images/OsbSanityUVSeams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityUVSeams.png -------------------------------------------------------------------------------- /docs/images/OsbSanityUVsInRightQuarter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityUVsInRightQuarter.png -------------------------------------------------------------------------------- /docs/images/OsbSanityVallence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityVallence.png -------------------------------------------------------------------------------- /docs/images/OsbSanityZeroLengthEdge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/OsbSanityZeroLengthEdge.png -------------------------------------------------------------------------------- /docs/images/SanityChecker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/docs/images/SanityChecker.png -------------------------------------------------------------------------------- /mel/checks/geo/osbSanity11EdgesAtOnePoint.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanity11EdgesAtOnePoint", 4 | "GEO CHECK", 5 | "Vallence check: No more than 11 edges going into one point", 6 | "This check makes sure there are no more than 11 edges meeting at\n\ 7 | one single vertex.If there are more then the fix will remove every second edge.", 8 | "Perform,Select,fix"); 9 | 10 | global proc osbSanity11EdgesAtOnePoint() 11 | { 12 | string $sl[] = getObjectsBasedOnPrefs(); 13 | select -cl; 14 | for ($s in $sl) 15 | { 16 | int $n[] = polyEvaluate("-v", $s); 17 | int $i; 18 | for ($i = 0; $i < $n[0]; $i++) 19 | { 20 | if (size(vertexToEdge($s, $i)) > 11) 21 | { 22 | select -add ($s+".vtx["+$i+"]"); 23 | } 24 | } 25 | } 26 | } 27 | 28 | proc int getComponentNumber(string $obj) 29 | { 30 | string $buffer[]; 31 | int $numTokens = `tokenize $obj "[" $buffer`; 32 | $numTokens = `tokenize $buffer[1] "]" $buffer`; 33 | int $face = $buffer[0]; 34 | return $face; 35 | } 36 | 37 | proc string getComponentObjName(string $obj) 38 | { 39 | string $buffer[]; 40 | int $numTokens = `tokenize $obj "." $buffer`; 41 | return $buffer[0]; 42 | } 43 | 44 | proc string reconstructComponentName(string $shape, string $type, int $component) 45 | { 46 | return $shape+"." + $type + "[" + $component + "]"; 47 | } 48 | 49 | global proc int[] tokenizePolyInfo(string $info) 50 | { 51 | string $tokens[]; 52 | tokenize $info " :\n\r" $tokens; 53 | 54 | int $order[]; 55 | clear $order; 56 | int $t; 57 | 58 | for ( $t = 2; $t < `size $tokens`; $t++ ) 59 | $order[`size $order`] = $tokens[$t]; 60 | 61 | return $order; 62 | } 63 | 64 | global proc int[] vertexToEdge(string $shape, int $vertex) 65 | { 66 | string $fte[] = polyInfo("-vertexToEdge",$shape+".vtx["+$vertex+"]"); 67 | return (tokenizePolyInfo($fte[0])); 68 | } 69 | 70 | global proc osbSanity11EdgesAtOnePointFix() 71 | { 72 | string $sl[] = ls("-sl","-fl"); 73 | string $delList[]; 74 | int $j = 0; 75 | for ($s in $sl) 76 | { 77 | // get edges connected to this vertex 78 | 79 | string $shape = getComponentObjName($s); 80 | int $vertex = getComponentNumber($s); 81 | int $edges[] = vertexToEdge($shape, $vertex); 82 | int $i = 0; 83 | for ($e in $edges) 84 | { 85 | // delete 1 out of every 2 86 | if ($i % 2 == 0) 87 | $delList[$j++] = reconstructComponentName($shape, "e", $e); 88 | $i++; 89 | } 90 | } 91 | delete $delList; 92 | } 93 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityBorders.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | global proc osbSanityBorders() 4 | { 5 | if (osbGetRunOnAllObjects()) 6 | select(ls("-exactType", "mesh")); 7 | polySelectConstraint -m 3 -t 0x8000 -w 1; 8 | polySelectConstraint -dis; 9 | } 10 | 11 | global proc osbSanityBordersFix() 12 | { 13 | for ($s in ls("-sl")) 14 | { 15 | polyCloseBorder -ch 1 $s; 16 | } 17 | select -cl; 18 | } 19 | 20 | osbAddSanityCheck( "osbSanityBorders", // name 21 | "GEO CHECK", // category 22 | "Open edges/border edges", // description 23 | "This check looks for open borders in polygon shells and the fix closes them.", // tooltip 24 | "Perform,Select,fix" // fix type 25 | ); 26 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityDeleteHistory.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityDeleteHistory", 4 | "GEO CHECK", 5 | "Delete all history", 6 | "This check deletes history on all nodes.", 7 | "Perform" 8 | ); 9 | 10 | global proc osbSanityDeleteHistory() 11 | { 12 | string $sl[] = getObjectsBasedOnPrefs(); 13 | for ($s in $sl) 14 | { 15 | if (objExists($s)) 16 | { 17 | select $s; 18 | DeleteHistory(); 19 | } 20 | } 21 | select -cl; 22 | } 23 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityDeleteLayersAndDagNodes.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityDeleteLayersAndDagNodes", 4 | "SCENE CHECK", 5 | "Delete layers/unimportant DAG nodes", 6 | "This check deletes as much redundant DAG nodes as possible,\n\ 7 | in essence everything that can get deleted without\n\ 8 | affecting the scene visually or behaviourally", 9 | "Perform"); 10 | 11 | // Checking tool: Delete Layers/Unimportant DAG Nodes 12 | global proc osbSanityDeleteLayersAndDagNodes() 13 | { 14 | performCleanUpSceneForEverything(); 15 | 16 | for ($s in `ls -exactType objectSet`) 17 | { 18 | if ($s != "defaultLightSet" && $s != "defaultObjectSet") 19 | { 20 | delete $s; 21 | } 22 | } 23 | 24 | for ($s in `ls -exactType displayLayer`) 25 | { 26 | if ($s != "defaultLayer") 27 | { 28 | delete $s; 29 | } 30 | } 31 | 32 | for ($s in `ls -exactType renderLayer`) 33 | { 34 | if ($s != "defaultRenderLayer") 35 | { 36 | delete $s; 37 | } 38 | } 39 | 40 | string $exactType[] = {"brush", "ikRPsolver", "ikSCsolver", "ikSplineSolver"}; 41 | 42 | for ($t in $exactType) 43 | { 44 | string $brushes[] = `ls -exactType $t`; 45 | for ($s in $brushes) 46 | delete $s; 47 | } 48 | 49 | deleteEmptyLayers("Display"); 50 | deleteEmptyLayers("Render"); 51 | 52 | if( size(`getenv "MAYA_TESTING_CLEANUP"`) == 0 ) 53 | print "You can be rid of the warning dialog box can setting the MAYA_TESTING_CLEANUP environment variable to 1 e.g adding export MAYA_TESTING_CLEANUP=1; to your .bashrc file in linux\n"; 54 | } 55 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityDeleteShadersApplyLambert.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityDeleteShadersApplyLambert", 4 | "GEO CHECK", 5 | "Delete shaders + assign lambert1 shader", 6 | "This check deletes all shaders in the scene and\n\ 7 | applies the default lambert material to all polygonal geometry", 8 | "Perform"); 9 | 10 | global proc osbSanityDeleteHistory() 11 | { 12 | string $sl[] = getObjectsBasedOnPrefs(); 13 | 14 | for ($s in $sl) 15 | { 16 | if (objExists($s)) 17 | { 18 | select $s; 19 | DeleteHistory(); 20 | } 21 | } 22 | select -cl; 23 | } 24 | 25 | // Delete shaders + assign lambert1 shader 26 | global proc osbSanityDeleteShadersApplyLambert() 27 | { 28 | string $meshes[] = getObjectsBasedOnPrefs(); 29 | 30 | for ($s in $meshes) 31 | assignSG lambert1 $s; 32 | scOpt_performOneCleanup( { "shaderOption" } ); 33 | if( size(`getenv "MAYA_TESTING_CLEANUP"`) == 0 ) 34 | print "You can be rid of the warning dialog box can setting the MAYA_TESTING_CLEANUP environment variable to 1 e.g adding export MAYA_TESTING_CLEANUP=1; to your .bashrc file in linux\n"; 35 | } 36 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityHolesBorder.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | global string $fixCommand = ""; 4 | 5 | global proc osbSanityHolesBorders() 6 | { 7 | if (osbGetRunOnAllObjects()) 8 | select(ls("-exactType", "mesh")); 9 | polySelectConstraint -m 3 -t 0x8000 -w 1; 10 | polySelectConstraint -dis; 11 | global string $fixCommand; 12 | $fixCommand = holesBorder(); 13 | 14 | } 15 | 16 | global proc osbSanityHolesBordersFix() 17 | { 18 | // holesBorder assumes that all border edges are already selected 19 | // and will fix one border edge only. 20 | global string $fixCommand; 21 | print("fix command: "+$fixCommand+"\n"); 22 | eval($fixCommand); 23 | } 24 | 25 | osbAddSanityCheck( "osbSanityHolesBorders", // name 26 | "GEO CHECK", // category 27 | "Add borders to holes", // description 28 | "This check looks for open borders in polygon shells and adds an edge loop to their border.", // tooltip 29 | "Perform,Select,fix" // fix type 30 | ); 31 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityLaminaFaces.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityLaminaFaces", 4 | "GEO CHECK", 5 | "No lamina faces", 6 | "Lamina Faces are faces that share the same edges (and thus the same vertices).\n\ 7 | You can think of Lamina Faces as unnecessary faces that sit right on top of each other.\n\ 8 | Objects with Lamina Faces will still render fine, but render time is likely to increase\n\ 9 | as the renderer will compute Lamina Faces twice. Any smooth operation will produce\n\ 10 | strange looking results and a SubD conversion will report a Nonmanifold error.\n\ 11 | Lamina faces usually occur when you merge vertices on faces that share the same space.", 12 | "Perform,Select,fix"); 13 | 14 | global proc osbSanityLaminaFaces() 15 | { 16 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"2","1","0","0","0","0","0","0","1e-05","0","1e-05","0","1e-05","0","-1","1" }; 17 | } 18 | 19 | global proc osbSanityLaminaFacesFix() 20 | { 21 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"1","1","0","0","0","0","0","0","1e-05","0","1e-05","0","1e-05","0","-2","1" }; 22 | } 23 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityMoreThanFourEdges.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityMoreThanFourEdges", 4 | "GEO CHECK", 5 | "No more than four sided polys", 6 | "Makes sure that no polygonal face has more than 4 edges.\n\ 7 | The Fix is performed by triangulating offending faces.", 8 | "Perform,Select,fix"); 9 | 10 | global proc osbSanityMoreThanFourEdges() 11 | { 12 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"2","1","0","1","0","0","0","0","1e-05","0","1e-05","0","1e-05","0","-2","0" }; 13 | } 14 | 15 | global proc osbSanityMoreThanFourEdgesFix() 16 | { 17 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"1","1","0","1","0","0","0","0","1e-05","0","1e-05","0","1e-05","0","-1","0" }; 18 | } 19 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityNonManifoldFaces.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityNonManifoldFaces", 4 | "GEO CHECK", 5 | "No non manifold faces", 6 | "Nonmanifold Geometry is simply put a Mesh that could not exist in the real world. \n\ 7 | Nonmanifold Geometry can be a real pain in the butt \n\ 8 | as Maya refuses to convert to Subdivisions, Booleans won't work and smooth \n\ 9 | operations can lead to strange results. There are three different types of nonmanifold \n\ 10 | Geometry (actually four since lamina faces are technically also nonmanifold):\n\ 11 | - Three or more faces share the same edge on an object\n\ 12 | - Two or more faces share the same vertex, yet they share no edge\n\ 13 | - Two or more adjacent faces have opposite normal directions\n\ 14 | Again, you should not let Maya do the work for you, but clean they geometry up yourself. Opposite normal \n\ 15 | directions are easily spotted by turning on Display->Polygons->Face Normals. Simply select the faces and \n\ 16 | use Normals->Reverse Normals or use Normals->Conform when dealing with a lot of inverse normals. \n\ 17 | When dealing with faces that share the same vertex you have to decide for yourself whether you want to \n\ 18 | split up the faces into separate objects or if you want to use 'Append to Polygon Tool' to \n\ 19 | connect the edges. Three or more faces that share the same edge can be a bit tricky. The best advice I \n\ 20 | can give you is to take a close look at your object and visualize how this object should look in the real world. \n\ 21 | Then delete the faces that should not be there.", 22 | "Perform,Select,fix"); 23 | 24 | global proc osbSanityNonManifoldFaces() 25 | { 26 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"2","1","0","0","0","0","0","0","1e-05","0","1e-05","0","1e-05","0","2","0" }; 27 | } 28 | 29 | global proc osbSanityNonManifoldFacesFix() 30 | { 31 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"1","1","0","0","0","0","0","0","1e-05","0","1e-05","0","1e-05","0","2","0" }; 32 | } 33 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityNormals.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityNormals", 4 | "GEO CHECK", 5 | "Check polygon normals facing the right direction", 6 | "This checks whether the normals for the object are facing 'outwards'.\n\ 7 | It uses a combination of two statistical methods to do so, and selects \n\ 8 | the method with the highest level of confidence. Please note that this\n\ 9 | check assumes that normals are conformed before running.", 10 | "Perform,Select,fix"); 11 | 12 | global proc osbSanityNormals() 13 | { 14 | string $meshes[] = getObjectsBasedOnPrefs(); 15 | select -cl; 16 | for ($s in $meshes) 17 | { 18 | print("checkNormalDirection + " + $s + "\n"); 19 | if (!objExists($s)) 20 | error($s + "does not exist\n"); 21 | string $dir = checkNormalDirection($s, 500); 22 | if ($dir == "inwards") 23 | select -add $s; 24 | } 25 | } 26 | 27 | global proc osbSanityNormalsFix() 28 | { 29 | string $ls[] = ls("-sl"); 30 | for ($s in $ls) 31 | polyNormal -normalMode 0 -userNormalMode 0 -ch 1 $s; 32 | } 33 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityWarnRefMaterial.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityWarnRefMaterial", 4 | "GEO CHECK", 5 | "Give warning if reference geo is in scene", 6 | "This checks whether there are any maya references\n\ 7 | left in the scene.", 8 | "Perform"); 9 | 10 | // Give warning if reference geo is in scene 11 | global proc osbSanityWarnRefMaterial() 12 | { 13 | string $refs[] = ls("-referencedNodes"); 14 | if (size($refs) > 0) 15 | { 16 | confirmDialog 17 | -title ("Referenced nodes") 18 | -message ("Warning this scene contains referenced geometry") 19 | -button "OK"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mel/checks/geo/osbSanityZeroLengthEdges.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityZeroLengthEdges", 4 | "GEO CHECK", 5 | "Floating vertex/zero edge length", 6 | "This checks for edges whose two vertices\n\ 7 | are less than 1e-05 units apart.", 8 | "Perform,Select,fix"); 9 | 10 | global proc osbSanityZeroLengthEdges() 11 | { 12 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"2","1","0","0","0","0","0","0","1e-05","1","0","0","1e-05","0","-1","0" }; 13 | } 14 | 15 | global proc osbSanityZeroLengthEdgesFix() 16 | { 17 | polyCleanupArgList 3 { (string)osbGetRunOnAllObjects(),"1","1","0","0","0","0","0","0","1e-05","1","1e-05","0","1e-05","0","-1","0" }; 18 | } 19 | -------------------------------------------------------------------------------- /mel/checks/naming/osbSanityNameClashes.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | if (!pluginInfo("-q", "-loaded", "osbTools")) 4 | loadPlugin "osbTools"; 5 | 6 | osbAddSanityCheck( "osbNameClashes", 7 | "NAMING CONVENSIONS", 8 | "Check that not objects have the same name", 9 | "This resolves name clashes for meshes in the scene.", 10 | "Perform"); 11 | -------------------------------------------------------------------------------- /mel/checks/naming/osbSanityNameEndings.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | if (!pluginInfo("-q", "-loaded", "osbTools")) 4 | loadPlugin "osbTools"; 5 | 6 | osbAddSanityCheck( "rwmPerformRenamingWithOptions", 7 | "NAMING CONVENSIONS", 8 | "Check that all geo and group nodes end in _GEO/_PLY/_GRP", 9 | "This checks that all nodes ends in _GEO/_PLY/_GRP\n\ 10 | if they are polygons with subd attributes, polygons, or groups, respectively.", 11 | "Perform"); 12 | 13 | global proc rwmPerformRenamingWithOptionsCallback() 14 | { 15 | int $grp = checkBox("-q", "-value", "osbGrpCB"); 16 | int $force = checkBox("-q", "-value", "osbForceCB"); 17 | int $plygeo = radioButtonGrp("-q", "-select", "osbPlyGeoRadio"); 18 | 19 | int $runOnAll = osbGetRunOnAllObjects(); 20 | 21 | print ($plygeo); 22 | 23 | osbTypeRename( $grp ? "grp" : "nogrp", $plygeo == 1 ? "ply" : $plygeo == 2 ? "geo" : "", $runOnAll ? "all" : "selection", $force); 24 | } 25 | 26 | global proc rwmPerformRenamingWithOptions() 27 | { 28 | string $window = "osbSceneRenaming"; 29 | if (window("-exists", $window)) 30 | deleteUI($window); 31 | window("-title", "osb Sanity Checking Tool", "-resizeToFitChildren", 1, "-menuBar", false, $window); 32 | 33 | columnLayout -columnAlign "center" -cw 450; 34 | checkBox -label "_GRP" "osbGrpCB"; 35 | radioButtonGrp -numberOfRadioButtons 2 -labelArray2 "_PLY" "_GEO" "osbPlyGeoRadio"; 36 | rowLayout -nc 2; 37 | button -label "perform" -command "rwmPerformRenamingWithOptionsCallback()"; 38 | checkBox -label "force _PLY|_GEO" "osbForceCB"; 39 | setParent ..; 40 | setParent ..; 41 | showWindow($window); 42 | 43 | window("-e", "-width", 150, "-height", 70, $window); 44 | } 45 | -------------------------------------------------------------------------------- /mel/checks/naming/osbSanityNumberPadding.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | if (pluginInfo("-q", "-l", "ResolveDuplicates.py")) 4 | { 5 | flushUndo(); 6 | unloadPlugin "ResolveDuplicates.py"; 7 | } 8 | 9 | if (pluginInfo("-q", "-l", "InheritParentsName.py")) 10 | { 11 | flushUndo(); 12 | unloadPlugin "InheritParentsName.py"; 13 | } 14 | 15 | loadPlugin "ResolveDuplicates.py"; 16 | loadPlugin "InheritParentsName.py"; 17 | 18 | if (!pluginInfo("-q", "-l", "-loaded", "osbTools")) 19 | loadPlugin "osbTools"; 20 | 21 | osbAddSanityCheck( "rwmPerformPaddingWithOptions", 22 | "NAMING CONVENSIONS", 23 | "Check that all geo and group nodes have a number padding", 24 | "This makes all meshes inherit the name of their parent group.\n\ 25 | It also numbers each object based on it's order in each particular group.", 26 | "Perform"); 27 | 28 | global proc rwmPerformPaddingWithOptionsCallback() 29 | { 30 | int $inheritParentName = checkBox("-q", "-value", "inheritParentName"); 31 | int $resolveDuplicates = checkBox("-q", "-value", "resolveDuplicates"); 32 | 33 | int $runOnAll = osbGetRunOnAllObjects(); 34 | 35 | if ($inheritParentName) 36 | newtonInheritParentsName(); 37 | 38 | if ($resolveDuplicates) 39 | newtonResolveDuplicates(); 40 | } 41 | 42 | global proc rwmPerformPaddingWithOptions() 43 | { 44 | string $window = "osbSceneRenaming"; 45 | if (window("-exists", $window)) 46 | deleteUI($window); 47 | window("-title", "osb Sanity Checking Tool", "-resizeToFitChildren", 1, "-menuBar", false, $window); 48 | 49 | columnLayout -columnAlign "center" -cw 450; 50 | checkBox -label "Inherit Parent's Name" "inheritParentName"; 51 | checkBox -label "Resolve Duplicates and padding" "resolveDuplicates"; 52 | 53 | button -label "perform" -command "rwmPerformPaddingWithOptionsCallback()"; 54 | 55 | showWindow($window); 56 | 57 | window("-e", "-width", 300, "-height", 150, $window); 58 | } 59 | -------------------------------------------------------------------------------- /mel/checks/transform/osbSanityFreezTransforms.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityFreezTransforms", 4 | "TRANSFORM CHECK", 5 | "Freeze transforms", 6 | "Freezes all transform nodes in the scene", 7 | "Perform"); 8 | 9 | global proc osbSanityFreezTransforms() 10 | { 11 | 12 | string $sl[]; 13 | 14 | if (osbGetRunOnAllObjects()) 15 | $sl = ls("-exactType","transform"); 16 | else 17 | $sl = ls("-sl"); 18 | 19 | for ($s in $sl) 20 | makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $s; 21 | } 22 | -------------------------------------------------------------------------------- /mel/checks/transform/osbSanityGeoAtZero.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityGeoAtZero", 4 | "TRANSFORM CHECK", 5 | "no geo below -0.005 in Y", 6 | "This check ensures that no geometry's bounding box is below -0.005", 7 | "Perform,Select,fix"); 8 | 9 | global proc osbSanityGeoAtZero() 10 | { 11 | string $sl[] = getObjectsBasedOnPrefs(); 12 | 13 | string $obj[]; 14 | 15 | for ($s in $sl) 16 | { 17 | float $bb[] = polyEvaluate("-b", $s); 18 | 19 | if ($bb[2] < -0.005) 20 | $obj[size($obj)] = $s; 21 | } 22 | select $obj; 23 | } 24 | -------------------------------------------------------------------------------- /mel/checks/transform/osbSanityTopGroupNodeToZero.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityTopGroupNodeToZero", 4 | "TRANSFORM CHECK", 5 | "Place top group node pivot to world 0", 6 | "This places the top level group node's pivot at world (0,0,0)\n\ 7 | This check will not work if there is more than 1 top group transform.", 8 | "Perform"); 9 | 10 | // Place top group node pivot to world 0 11 | global proc osbSanityTopGroupNodeToZero() 12 | { 13 | // get all transforms that don't have any parents 14 | 15 | string $trans[] = ls("-exactType", "transform"); 16 | string $topLevel[]; 17 | for ($s in $trans) 18 | if (size(getParents($s)) == 0 && ($s != "top" && $s != "side" && $s != "front" && $s != "persp")) 19 | $topLevel[size($topLevel)] = $s; 20 | 21 | // there can be only one 22 | if (size($topLevel) > 1) 23 | { 24 | confirmDialog 25 | -title ("Top Level Nodes") 26 | -message ("Warning there is more than 1 top level node") 27 | -button "OK"; 28 | } 29 | 30 | if (size($topLevel) == 1) 31 | move 0 0 0 ($topLevel[0]+".scalePivot") ($topLevel[0]+".rotatePivot"); 32 | } 33 | 34 | global proc string[] getParents(string $obj) 35 | { 36 | string $relatives[] = listRelatives("-parent", "-f", $obj); 37 | return $relatives; 38 | } 39 | -------------------------------------------------------------------------------- /mel/checks/uv/osbSanityUVBorders.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityUVBorders", 4 | "UV CHECKING", 5 | "Check there are no open UV seams", 6 | "This checks there are no seams within a UV shell.\n\ 7 | A seam is when two UV edges are perfectly adjacent.", 8 | "Perform,Select,fix"); 9 | 10 | global proc osbSanityUVBorders() 11 | { 12 | string $meshes[] = getObjectsBasedOnPrefs(); 13 | select -cl; 14 | for ($s in $meshes) 15 | UVSeams($s); 16 | } 17 | -------------------------------------------------------------------------------- /mel/checks/uv/osbSanityUVOverlapping.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityUVOverlapping", 4 | "UV CHECKING", 5 | "Check no UV edges are overlapping a tile border", 6 | "Check that no UVs are overlapping a tile border\n\ 7 | This is important as all the UVs per object\n\ 8 | need to fit within one grid tile.", 9 | "Perform,Select,fix"); 10 | 11 | // Check no UV edges are overlapping a tile border 12 | global proc osbSanityUVOverlapping() 13 | { 14 | float $threshold = 0.001; 15 | string $meshes[] = getObjectsBasedOnPrefs(); 16 | select -cl; 17 | for ($s in $meshes) 18 | { 19 | int $i; 20 | int $n[] = polyEvaluate("-uv", $s); 21 | 22 | float $centroidx = 0; 23 | float $centroidy= 0; 24 | 25 | float $maxx = -1e6; 26 | float $maxy = -1e6; 27 | float $minx = 1e6; 28 | float $miny = 1e6; 29 | 30 | for ($i = 0; $i < $n[0]; $i++) 31 | { 32 | float $p[] = polyEditUV("-q", $s+".map["+$i+"]"); 33 | $centroidx += $p[0]; 34 | $centroidy += $p[1]; 35 | if ($p[0] > $maxx) $maxx = $p[0]; 36 | if ($p[1] > $maxy) $maxy = $p[1]; 37 | if ($p[0] < $minx) $minx = $p[0]; 38 | if ($p[1] < $miny) $miny = $p[1]; 39 | } 40 | $centroidx /= $n[0]; 41 | $centroidy /= $n[0]; 42 | 43 | int $quadrantx = floor($centroidx); 44 | int $quadranty = floor($centroidy); 45 | 46 | if ($minx - $quadrantx < $threshold || $miny - $quadranty < $threshold || $maxx - ($quadrantx+1) > $threshold || $maxy - ($quadranty+1) > $threshold) 47 | select -add $s; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /mel/checks/uv/osbSanityUVShellsOverlapping.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityUVShellsOverlapping", 4 | "UV CHECKING", 5 | "Check no UVs/ UV shells are overlapping each other", 6 | "UV Shells should not overlap since they'll inherit the same texture pixels if they do.\n\ 7 | This check makes sure no shells within the same object overlap.", 8 | "Perform,Select,fix"); 9 | 10 | global proc osbSanityUVShellsOverlapping() 11 | { 12 | string $meshes[] = getObjectsBasedOnPrefs(); 13 | select -cl; 14 | for ($s in $meshes) 15 | { 16 | int $overlapping = OverlappingUVShells($s); 17 | if ($overlapping == 1) 18 | select -add $s; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mel/checks/uv/osbSanityUVsInRightGrid.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityUVsInRightGrid", 4 | "UV CHECKING", 5 | "Check no UVs are in -1 tiles in Y and X", 6 | "Make sure UVs are only in the positive areas of the UV grid.", 7 | "Perform,Select,fix"); 8 | 9 | global proc osbSanityUVsInRightGrid() 10 | { 11 | string $sl[] = getObjectsBasedOnPrefs(); 12 | select -cl; 13 | for ($s in $sl) 14 | { 15 | int $i; 16 | int $n[] = polyEvaluate("-uv", $s); 17 | for ($i = 0; $i < $n[0]; $i++) 18 | { 19 | float $p[] = polyEditUV("-q", $s+".map["+$i+"]"); 20 | if ($p[0] < 0 || $p[1] < 0) 21 | select -add ($s+".map["+$i+"]"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /mel/checks/uv/osbSanityUVsReversed.mel: -------------------------------------------------------------------------------- 1 | source "osbSanityCheckerAPI.mel"; 2 | 3 | osbAddSanityCheck( "osbSanityUVsReversed", 4 | "UV CHECKING", 5 | "Check no UVs are reversed/inverted (like poly normals)", 6 | "This checks that no UVs are facing down, to make sure\n\ 7 | textures don't show up inverted.", 8 | "Perform,Select,fix"); 9 | 10 | global proc osbSanityUVsReversed() 11 | { 12 | string $meshes[] = getObjectsBasedOnPrefs(); 13 | select -cl; 14 | for ($s in $meshes) 15 | UVReversed($s); 16 | } 17 | -------------------------------------------------------------------------------- /mel/osbSanityChecker.mel: -------------------------------------------------------------------------------- 1 | loadPlugin "osbTools"; 2 | 3 | source "osbSanityCheckerAPI.mel"; 4 | source "cleanUpScene.mel"; // overridden to remove a confirm dialog 5 | 6 | source "checks/geo/osbSanityBorders.mel"; 7 | source "checks/geo/osbSanityHolesBorder.mel"; 8 | source "checks/geo/osbSanityZeroLengthEdges.mel"; 9 | source "checks/geo/osbSanityMoreThanFourEdges.mel"; 10 | source "checks/geo/osbSanityNonManifoldFaces.mel"; 11 | source "checks/geo/osbSanityLaminaFaces.mel"; 12 | source "checks/geo/osbSanityDeleteShadersApplyLambert.mel"; 13 | source "checks/geo/osbSanityWarnRefMaterial.mel"; 14 | source "checks/geo/osbSanity11EdgesAtOnePoint.mel"; 15 | source "checks/geo/osbSanityNormals.mel"; 16 | source "checks/geo/osbSanityDeleteHistory.mel"; 17 | 18 | source "checks/transform/osbSanityFreezTransforms.mel"; 19 | source "checks/transform/osbSanityTopGroupNodeToZero.mel"; 20 | source "checks/transform/osbSanityGeoAtZero.mel"; 21 | 22 | source "checks/naming/osbSanityNumberPadding.mel"; 23 | source "checks/naming/osbSanityNameEndings.mel"; 24 | 25 | source "checks/uv/osbSanityUVBorders.mel"; 26 | source "checks/uv/osbSanityUVOverlapping.mel"; 27 | source "checks/uv/osbSanityUVShellsOverlapping.mel"; 28 | source "checks/uv/osbSanityUVsReversed.mel"; 29 | source "checks/uv/osbSanityUVsInRightGrid.mel"; 30 | source "checks/geo/osbSanityDeleteLayersAndDagNodes.mel"; 31 | 32 | source "osbUserChecks.mel"; 33 | 34 | buildSanityCheckUI(); 35 | -------------------------------------------------------------------------------- /mel/osbSanityCheckerAPI.mel: -------------------------------------------------------------------------------- 1 | // "I am rarely happier than when spending entire day programming my computer to 2 | // perform automatically a task that it would otherwise take me a good ten seconds to do by hand." 3 | // - Douglas Adams 4 | 5 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// 6 | ////////////////////////////////////////////HELPER FUNCTIONS////////////////////////////////////////////// 7 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// 8 | 9 | global proc string determineSetContent(string $set) 10 | { 11 | string $content[] = `sets -q $set`; 12 | for ($c in $content) 13 | { 14 | if ( 15 | gmatch($c, "*.map*") || 16 | gmatch($c, "*.vtx*") || 17 | gmatch($c, "*.f*") || 18 | gmatch($c, "*.e*")) 19 | return "component"; 20 | } 21 | if (size($content) == 0) 22 | return "empty"; 23 | return "object"; 24 | } 25 | 26 | global proc int osbGetRunOnAllObjects() 27 | { 28 | return menuItem("-q", "-checkBox", "osbRunOnAllGeoCB"); 29 | } 30 | 31 | global proc string getMesh(string $obj) 32 | { 33 | string $type = objectType($obj); 34 | 35 | if ($type == "mesh") 36 | return $obj; 37 | else if ($type == "transform") 38 | { 39 | string $shapes[] = listRelatives("-type", "mesh", $obj); 40 | return $shapes[0]; 41 | } 42 | error("Don't get here"); 43 | } 44 | 45 | global proc string[] getMeshesFromSelection() 46 | { 47 | string $sl[] = ls("-sl"); 48 | string $meshes[]; 49 | for ($s in $sl) 50 | $meshes[size($meshes)] = getMesh($s); 51 | return $meshes; 52 | } 53 | 54 | global proc string[] getObjectsBasedOnPrefs() 55 | { 56 | string $sl[]; 57 | 58 | if (osbGetRunOnAllObjects()) 59 | $sl = ls("-exactType", "mesh"); 60 | else 61 | $sl = getMeshesFromSelection(); 62 | return $sl; 63 | } 64 | 65 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// 66 | //////////////////////////////////////////////UI BUILDING///////////////////////////////////////////////// 67 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// 68 | 69 | proc createCheckItem(string $name, string $text, string $help, int $enable) 70 | { 71 | rowLayout -numberOfColumns 2 -columnWidth 1 400 ($name+"Layout"); 72 | checkBox -annotation $help -enable $enable -label $text ($name+"CB"); 73 | button -label "perform" -enable $enable -c $name ($name+"PerformButton"); 74 | setParent ..; 75 | } 76 | 77 | proc createGeoCheckItem(string $name, string $text, string $help, int $enable) 78 | { 79 | int $setHasObjs = objExists($name+"_set") && sets("-q", "-size", $name+"_set") != 0; 80 | rowLayout -numberOfColumns 4 -columnWidth 1 400 ($name+"Layout"); 81 | checkBox -annotation $help -enable $enable -label $text ($name+"CB"); 82 | button("-label", "check", "-enable", $enable, "-c", ("performPolyChecksCallback(\""+$name+"\")"), ($name+"PerformButton")); 83 | button("-label", "select", "-enable", ($enable && $setHasObjs), "-c", ("selectCheckedItems(\""+$name+"\");"), ($name+"SelectButton")); 84 | if (exists($name + "Fix")) 85 | button("-label", "fix", "-enable", ($enable && $setHasObjs), "-c", "performPolyFixsCallback(\""+$name+"\")", ($name+"FixButton")); 86 | setParent ..; 87 | } 88 | 89 | // Sorry about these global vars, really couldn't find another way. 90 | global string $osbSanityChecks[]; 91 | global string $osbSanityCategories[]; 92 | global string $osbSanityDescriptions[]; 93 | global string $osbSanityHelp[]; 94 | global string $osbSanityTypes[]; 95 | 96 | clear $osbSanityChecks; 97 | clear $osbSanityCategories; 98 | clear $osbSanityDescriptions; 99 | clear $osbSanityHelp; 100 | clear $osbSanityTypes; 101 | 102 | global proc osbAddSanityCheck(string $name, string $category, string $description, string $help, string $type) 103 | { 104 | global string $osbSanityChecks[]; 105 | global string $osbSanityDescriptions[]; 106 | global string $osbSanityHelp[]; 107 | global string $osbSanityCategories[]; 108 | global string $osbSanityTypes[]; 109 | 110 | $osbSanityChecks[size($osbSanityChecks)] = $name; 111 | $osbSanityDescriptions[size($osbSanityDescriptions)] = $description; 112 | $osbSanityHelp[size($osbSanityHelp)] = $help == "" ? $description : $help; 113 | $osbSanityCategories[size($osbSanityCategories)] = $category; 114 | $osbSanityTypes[size($osbSanityTypes)] = $type; 115 | } 116 | 117 | // gets individual categories 118 | // ASSUMES CATEGORIES ARE SORTED 119 | proc string[] getIndividualCategories() 120 | { 121 | global string $osbSanityCategories[]; 122 | string $cats[]; 123 | string $prev; 124 | for ($c in $osbSanityCategories) 125 | { 126 | if ($c != $prev) 127 | $cats[size($cats)] = $c; 128 | $prev = $c; 129 | } 130 | return $cats; 131 | } 132 | 133 | global proc osbSaveAsPreset() 134 | { 135 | 136 | } 137 | 138 | global proc buildSanityCheckUI() 139 | { 140 | global string $osbSanityChecks[]; 141 | global string $osbSanityDescriptions[]; 142 | global string $osbSanityCategories[]; 143 | global string $osbSanityTypes[]; 144 | global string $osbSanityHelp[]; 145 | 146 | string $window = "SanityChecking"; 147 | 148 | if (window("-exists", $window)) 149 | deleteUI($window); 150 | 151 | window("-title", "osb Sanity Checking Tool", "-resizeToFitChildren", 1, "-menuBar", true, $window); 152 | 153 | int $height = 1; 154 | 155 | menu -label "Edit" -tearOff true; 156 | menuItem -label "Hide Checked Items" -c "osbHideCheckedItemsCallback()"; 157 | menuItem -label "Reset" -c "osbResetCallback()"; 158 | 159 | int $osbRunOnAllGeo = optionVar("-ex", "osbRunOnAllGeo") == false || optionVar("-q", "osbRunOnAllGeo"); 160 | 161 | menuItem -checkBox $osbRunOnAllGeo -label "Run on all geometry" -c "osbRunOnAllGeoCallback()" "osbRunOnAllGeoCB" ; 162 | 163 | menu -label "Help" -tearOff true; 164 | menuItem -label "Documentation" -c "osbSanityHelp()"; 165 | 166 | scrollLayout -childResizable true osbSanityMainScrollLayout; 167 | columnLayout -adjustableColumn true osbSanityMainColLayout; 168 | int $hasCheck = false; 169 | for ($i = 0; $i < size($osbSanityChecks); $i++) 170 | { 171 | string $category = substituteAllString($osbSanityCategories[$i]," ", "_"); 172 | 173 | int $showOption = optionVar("-ex", $osbSanityChecks[$i]) == false || optionVar("-q", $osbSanityChecks[$i]); 174 | 175 | if ($showOption) 176 | { 177 | // If the category does not yet exist 178 | if (columnLayout("-q", "-ex", ($category+"cl")) == 0) 179 | { 180 | // Create it 181 | setParent osbSanityMainColLayout; 182 | frameLayout -label $osbSanityCategories[$i] -borderStyle "etchedIn" $category; 183 | columnLayout($category+"cl"); 184 | $height += 21; 185 | } 186 | // Else set it as current layout 187 | else 188 | { 189 | setParent ($category+"cl"); 190 | } 191 | 192 | $height += 26; 193 | 194 | if ($osbSanityTypes[$i] == "Perform,Select,fix") 195 | createGeoCheckItem($osbSanityChecks[$i], $osbSanityDescriptions[$i], $osbSanityHelp[$i], 1); 196 | else 197 | createCheckItem($osbSanityChecks[$i], $osbSanityDescriptions[$i], $osbSanityHelp[$i], 1); 198 | } 199 | } 200 | setParent osbSanityMainScrollLayout; 201 | button -label "perform" -command "osbSanityCheck"; 202 | $height += 70; 203 | 204 | showWindow($window); 205 | 206 | window("-edit", "-height", $height, $window); 207 | } 208 | 209 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// 210 | ///////////////////////////////////////////////CALLBACKS////////////////////////////////////////////////// 211 | ////////////////////////////////////////////////////////////////////////////////////////////////////////// 212 | 213 | global proc osbRunOnAllGeoCallback() 214 | { 215 | int $cb = menuItem("-q", "-checkBox", "osbRunOnAllGeoCB"); 216 | optionVar("-iv", "osbRunOnAllGeo", $cb); 217 | } 218 | 219 | global proc osbSanityHelp() 220 | { 221 | system("/opt/google/chrome/google-chrome --auth-server-whitelist=\"*\" \"http://vfxwiki/index.php/OsbTools\" > /dev/null & disown"); 222 | print "Opened help in Chrome\n"; 223 | } 224 | 225 | global proc osbResetCallback() 226 | { 227 | global string $osbSanityChecks[]; 228 | for ($s in $osbSanityChecks) 229 | optionVar("-iv", $s, 1); 230 | evalDeferred("buildSanityCheckUI()"); 231 | } 232 | 233 | global proc osbHideCheckedItemsCallback() 234 | { 235 | global string $osbSanityChecks[]; 236 | for ($s in $osbSanityChecks) 237 | if (checkBox("-q", "-exists", $s+"CB") && checkBox("-q", "-value", $s+"CB")) 238 | optionVar("-iv", $s, 0); 239 | evalDeferred("buildSanityCheckUI()"); 240 | } 241 | 242 | global proc performPolyChecksCallback(string $name) 243 | { 244 | string $sl[] = ls("-sl"); 245 | 246 | // perform the check 247 | eval($name+"();"); 248 | // store into a set 249 | 250 | string $setName = $name+"_set"; 251 | 252 | if (objExists($setName) == 1) 253 | delete $setName; 254 | 255 | if (size(ls("-sl")) != 0) 256 | sets -text $setName -name $setName; 257 | 258 | button("-e", "-enable", objExists($setName) && sets("-q", "-size", $setName) != 0, ($name+"SelectButton")); 259 | if (exists($name + "Fix")) 260 | button("-e", "-enable", objExists($setName) && sets("-q", "-size", $setName) != 0 && exists($name + "Fix"), ($name+"FixButton")); 261 | 262 | select -cl; 263 | changeSelectMode -object; 264 | select $sl; 265 | } 266 | 267 | global proc performPolyFixsCallback(string $name) 268 | { 269 | eval($name+"Fix"); 270 | print ("Performing fix " + $name+"Fix"); 271 | } 272 | 273 | global proc selectCheckedItems(string $name) 274 | { 275 | string $set = ($name + "_set"); 276 | 277 | string $type = determineSetContent($set); 278 | 279 | if ($type != "empty") 280 | { 281 | if ($type == "component") 282 | { 283 | changeSelectMode -component; 284 | string $nodes[] = sets("-q", "-nodesOnly", $set); 285 | for ($n in $nodes) 286 | { 287 | hilite $n; 288 | } 289 | } 290 | select($set); 291 | } 292 | } 293 | 294 | global proc osbSanityCheck() 295 | { 296 | global string $osbSanityChecks[]; 297 | 298 | for ($c in $osbSanityChecks) 299 | if (checkBox("-q", "-value", $c) == 1) 300 | performPolyChecksCallback($c); 301 | } 302 | -------------------------------------------------------------------------------- /mel/osbUserChecks.mel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shyal/osbTools/2bf9ea03257ea331fe1065fb237c565305bcf15a/mel/osbUserChecks.mel -------------------------------------------------------------------------------- /osbTools.mod.in: -------------------------------------------------------------------------------- 1 | + osbTools @OSBTOOLS_MAJOR_VERSION@.@OSBTOOLS_MINOR_VERSION@.@OSBTOOLS_PATCH_VERSION@ . 2 | PYTHONPATH +:= python 3 | MAYA_SCRIPT_PATH +:= scripts 4 | -------------------------------------------------------------------------------- /py/InheritParentsName.py: -------------------------------------------------------------------------------- 1 | import maya.OpenMayaMPx as OpenMayaMPx 2 | import maya.OpenMaya as OpenMaya 3 | from sys import * 4 | import re 5 | from string import * 6 | from types import * 7 | import maya.cmds as cmds 8 | import NewtonRenaming 9 | 10 | reload(NewtonRenaming) 11 | 12 | from NewtonRenaming import * 13 | 14 | class RenameOperation(): 15 | newName = "" 16 | oldName = "" 17 | node = OpenMaya.MFnDependencyNode() 18 | path = OpenMaya.MDagPath() 19 | 20 | def __init__(self, nn, p): 21 | self.newName = nn 22 | self.node = OpenMaya.MFnDependencyNode(p.node()) 23 | self.oldName = self.node.name() 24 | self.path = p 25 | 26 | def redo(self): 27 | self.node.setName(self.newName) 28 | 29 | def undo(self): 30 | self.node.setName(self.oldName) 31 | 32 | def redoShortName(self): 33 | short = getShortName(self.newName) 34 | setShortName(short, self.path) 35 | 36 | def undoShortName(self): 37 | self.node.setName(self.oldName) 38 | 39 | class InheritParentsName(OpenMayaMPx.MPxCommand): 40 | 41 | operations = [] 42 | 43 | def __init__(self): 44 | OpenMayaMPx.MPxCommand.__init__(self) 45 | 46 | def doIt(self, args): 47 | 48 | iterObj = OpenMaya.MItDag(OpenMaya.MItDag.kDepthFirst, OpenMaya.MFn.kMesh) 49 | 50 | idd = 0 51 | 52 | self.operations = [] 53 | 54 | while not iterObj.isDone(): 55 | dPath = OpenMaya.MDagPath( ) 56 | iterObj.getPath( dPath ) 57 | 58 | dPath.pop() 59 | 60 | transformName = "" 61 | 62 | names = split(dPath.fullPathName(), "|") 63 | parentName = names[-2] 64 | op = RenameOperation(parentName, dPath) 65 | 66 | self.operations += [op] 67 | 68 | iterObj.next() 69 | 70 | self.redoIt() 71 | 72 | def redoIt(self): 73 | print "redoing" 74 | for op in self.operations: 75 | op.redoShortName() 76 | 77 | def undoIt(self): 78 | print "undoing" 79 | for op in self.operations: 80 | op.undoShortName() 81 | 82 | def isUndoable(self): 83 | return True 84 | 85 | def cmdCreator(): 86 | return OpenMayaMPx.asMPxPtr( InheritParentsName() ) 87 | 88 | def initializePlugin(mobject): 89 | mplugin = OpenMayaMPx.MFnPlugin(mobject, "Author", "1.0", "Any") 90 | try: 91 | mplugin.registerCommand( "newtonInheritParentsName", cmdCreator) 92 | except: 93 | print( "Failed to register command: %s\n" % "newtonInheritParentsName" ) 94 | raise 95 | 96 | def uninitializePlugin(mobject): 97 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 98 | try: 99 | mplugin.deregisterCommand( "newtonInheritParentsName" ) 100 | except: 101 | stderr.stdout.write( "Failed to unregister command: %s\n" % "newtonInheritParentsName" ) 102 | raise 103 | -------------------------------------------------------------------------------- /py/NewtonRenaming.py: -------------------------------------------------------------------------------- 1 | import maya.OpenMayaMPx as OpenMayaMPx 2 | import maya.OpenMaya as OpenMaya 3 | from sys import * 4 | import re 5 | from string import * 6 | from types import * 7 | import maya.cmds as cmds 8 | 9 | def hasPadding(name): 10 | m = re.search('_(\d+)', name) 11 | return True if m != None and m.group(0) != "" else False 12 | 13 | def hasType(name): 14 | m = re.search('(PLY|GEO|GRP)', name) 15 | return True if m != None and m.group(0) != "" else False 16 | 17 | def getType(name): 18 | m = re.search('(PLY|GEO|GRP)', name) 19 | return m.group(0) if m != None and m.group(0) != "" else "" 20 | 21 | def getLeafName(aFullPath): 22 | names = split(aFullPath.fullPathName(), "|") 23 | objName = names[-1] 24 | return objName 25 | 26 | def setNumberPadding(name, number): 27 | if hasPadding(name): 28 | ns = str(number) 29 | ns = ns.zfill(3) 30 | name = re.sub(r'_(\d+)', ns, name) 31 | return name 32 | 33 | def removeTrailingNumbers(name): 34 | name = re.sub(r'\d*$', '', name) 35 | return name 36 | 37 | def getShortName(name): 38 | name = re.sub(r'_(PLY|GEO|GRP)', '', name) 39 | name = re.sub(r'_(\d+)', '', name) 40 | name = re.sub(r'_*$', '', name) 41 | return name 42 | 43 | def setShortName(newName, dPath): 44 | dep = OpenMaya.MFnDependencyNode(dPath.node()) 45 | name = dep.name() 46 | 47 | shortName = getShortName(name) 48 | 49 | name = re.sub(shortName, newName, name) 50 | dep.setName(name) 51 | 52 | #unit tests 53 | 54 | sn = getShortName("taj_roof_001_PLY") 55 | if sn != "taj_roof": 56 | print "error in getShortName -> taj_roof_001_PLY should return taj_roof but returned: " + sn + "\n" 57 | raise AssertionError 58 | 59 | sn = getShortName("taj_roof_PLY") 60 | if sn != "taj_roof": 61 | print "error in getShortName -> taj_roof_PLY should return taj_roof but returned: " + sn + "\n" 62 | raise AssertionError 63 | 64 | sn = getShortName("taj1_roof_PLY") 65 | if sn != "taj1_roof": 66 | print "error in getShortName -> taj_roof_PLY should return taj1_roof but returned: " + sn + "\n" 67 | raise AssertionError 68 | 69 | sn = getShortName("taj1roof_PLY") 70 | if sn != "taj1roof": 71 | print "error in getShortName -> taj_roof_PLY should return taj1roof but returned: " + sn + "\n" 72 | raise AssertionError 73 | 74 | sn = getShortName("taj1_PLY") 75 | if sn != "taj1": 76 | print "error in getShortName -> taj_roof_PLY should return taj1 but returned: " + sn + "\n" 77 | raise AssertionError 78 | 79 | sn = getShortName("taj_roof_") 80 | if sn != "taj_roof": 81 | print "error in getShortName -> taj_roof_PLY should return taj_roof but returned: " + sn + "\n" 82 | raise AssertionError 83 | 84 | -------------------------------------------------------------------------------- /py/ResolveDuplicates.py: -------------------------------------------------------------------------------- 1 | import maya.OpenMayaMPx as OpenMayaMPx 2 | import maya.OpenMaya as OpenMaya 3 | from sys import * 4 | import re 5 | from string import * 6 | from types import * 7 | import maya.cmds as cmds 8 | import NewtonRenaming 9 | 10 | from unittest import * 11 | 12 | reload(NewtonRenaming) 13 | 14 | from NewtonRenaming import * 15 | 16 | # Objects in maya are composed of three elements according to our naming scheme: 17 | # __ 18 | # 19 | # the numbering has a padding of 3 by default, but can get bigger (say if group has 1000 objects 20 | # or more 21 | # 22 | # the type is either GRP GEO or PLY 23 | 24 | # Objects which have the same shortname are considered to be duplicates 25 | class Duplicate(): 26 | 27 | # number of times this shortname appears 28 | count = 0 29 | 30 | # dag paths to these objects 31 | paths = [] 32 | 33 | # initialise local vars properly 34 | def __init__(self): 35 | self.count = 1 36 | self.paths = [] 37 | 38 | 39 | # Atomic rename operation, can be done and undone 40 | class RenameOperation(): 41 | 42 | # new name of the object 43 | newName = "" 44 | 45 | # old name of the object (for undo) 46 | oldName = "" 47 | 48 | # this is for numering / number padding purposes 49 | numbering = 0 50 | 51 | # Maya MFnDependencyNode we want to rename 52 | node = OpenMaya.MFnDependencyNode() 53 | 54 | # Maya DagPath we want to rename 55 | path = OpenMaya.MDagPath() 56 | 57 | def __init__(self, shortName, numbering, path): 58 | 59 | self.numbering = numbering 60 | self.node = OpenMaya.MFnDependencyNode(path.node()) 61 | self.oldName = self.node.name() 62 | self.path = path 63 | 64 | ns = str(numbering) 65 | ns = ns.zfill(3) 66 | 67 | self.newName = shortName + "_" + ns 68 | 69 | if hasType(self.oldName): 70 | self.newName = self.newName + "_" + getType(self.oldName) 71 | 72 | def redo(self): 73 | self.node.setName(self.newName) 74 | 75 | def undo(self): 76 | self.node.setName(self.oldName) 77 | 78 | 79 | # Main class for resolving name clashes in the scene 80 | class ResolveDuplicates(OpenMayaMPx.MPxCommand): 81 | 82 | # holds operations that need to be performed 83 | # in redo / undo 84 | operations = [] 85 | 86 | def __init__(self): 87 | OpenMayaMPx.MPxCommand.__init__(self) 88 | 89 | def doIt(self, args): 90 | 91 | # this dictionary keeps track of how many times each object 92 | # has been encountered, i.e the key is a short name 93 | # the value is the number of times that short name was 94 | # encountered 95 | groupCounts = {} 96 | geoCounts = {} 97 | 98 | # clear operations on new call 99 | # to doIt 100 | self.operations = [] 101 | 102 | # iterate over each and every tranform in the scene 103 | iterObj = OpenMaya.MItDag(OpenMaya.MItDag.kDepthFirst, OpenMaya.MFn.kTransform) 104 | 105 | while not iterObj.isDone(): 106 | 107 | # get object's dag path 108 | dPath = OpenMaya.MDagPath() 109 | iterObj.getPath(dPath) 110 | 111 | # get leaf's name 112 | transformName = getLeafName(dPath) 113 | 114 | # skip out cameras 115 | if (transformName != "persp" and transformName != "top" and transformName != "side" and transformName != "front"): 116 | 117 | # get name minus numbering or type 118 | shortName = getShortName(transformName) 119 | 120 | utilx = OpenMaya.MScriptUtil() 121 | ptr = utilx.asUintPtr() 122 | 123 | dPath.numberOfShapesDirectlyBelow(ptr) 124 | 125 | numShapes = OpenMaya.MScriptUtil.getUint (ptr) 126 | 127 | isGeo = True if numShapes >= 1 else False 128 | 129 | if (isGeo): 130 | 131 | # how many times has this short name been encountered? 132 | count = groupCounts[shortName].count if shortName in groupCounts.keys() else None 133 | 134 | # if never, then set it to 1 135 | if (count is None): 136 | dup = Duplicate() 137 | dup.count = 1 138 | dup.paths.append(dPath) 139 | groupCounts[shortName] = dup 140 | else: 141 | # else increment it 142 | groupCounts[shortName].count += 1 143 | groupCounts[shortName].paths.append(dPath) 144 | 145 | else: 146 | # how many times has this short name been encountered? 147 | count = geoCounts[shortName].count if shortName in geoCounts.keys() else None 148 | 149 | # if never, then set it to 1 150 | if (count is None): 151 | dup = Duplicate() 152 | dup.count = 1 153 | dup.paths.append(dPath) 154 | geoCounts[shortName] = dup 155 | else: 156 | # else increment it 157 | geoCounts[shortName].count += 1 158 | geoCounts[shortName].paths.append(dPath) 159 | 160 | iterObj.next() 161 | 162 | self.resolveNames(groupCounts) 163 | self.resolveNames(geoCounts) 164 | 165 | self.redoIt() 166 | 167 | def resolveNames(self, counts): 168 | # loop over each short name's duplicates 169 | for it in counts.items(): 170 | # if a short name has been encountered more than once 171 | if (it[1].count >= 1): 172 | i = 1 173 | # for each object with the same short name 174 | for dPath in it[1].paths: 175 | names = split(dPath.fullPathName(), "|") 176 | objName = names[-1] 177 | shortName = getShortName(objName) 178 | op = RenameOperation(shortName, i, dPath) 179 | i = i + 1 180 | self.operations += [op] 181 | 182 | 183 | def redoIt(self): 184 | 185 | for op in self.operations: 186 | op.redo() 187 | 188 | def undoIt(self): 189 | 190 | for op in self.operations: 191 | op.undo() 192 | 193 | def isUndoable(self): 194 | return True 195 | 196 | def cmdCreator(): 197 | return OpenMayaMPx.asMPxPtr( ResolveDuplicates() ) 198 | 199 | def initializePlugin(mobject): 200 | mplugin = OpenMayaMPx.MFnPlugin(mobject, "Author", "1.0", "Any") 201 | try: 202 | mplugin.registerCommand( "newtonResolveDuplicates", cmdCreator) 203 | except: 204 | stderr.stdout.write( "Failed to register command: %s\n" % "newtonResolveDuplicates" ) 205 | raise 206 | 207 | def uninitializePlugin(mobject): 208 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 209 | try: 210 | mplugin.deregisterCommand( "newtonResolveDuplicates" ) 211 | except: 212 | stderr.stdout.write( "Failed to unregister command: %s\n" % "newtonResolveDuplicates" ) 213 | raise 214 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(SOURCE_FILES 3 | pluginMain.cpp 4 | holesBorder.cpp 5 | holesBorder.h 6 | triangleOverlappingTest.cpp 7 | UVReversed.cpp 8 | UVReversed.h 9 | overlappingUVShells.cpp 10 | overlappingUVShells.h 11 | UVCommon.cpp 12 | UVCommon.h 13 | intersect.cpp 14 | intersect.h 15 | Renaming.cpp 16 | Renaming.h 17 | UVSeams.cpp 18 | UVSeams.h 19 | ) 20 | 21 | find_package(Maya REQUIRED) 22 | find_package(Boost REQUIRED) 23 | 24 | include_directories(${MAYA_INCLUDE_DIR} ${Boost_INCLUDE_DIR}) 25 | link_directories(${MAYA_LIBRARY_DIR}) 26 | 27 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) 28 | 29 | if (WIN32) 30 | set_target_properties(${PROJECT_NAME} PROPERTIES 31 | LINK_FLAGS "/export:initializePlugin /export:uninitializePlugin") 32 | set_target_properties(${PROJECT_NAME} PROPERTIES 33 | PREFIX "" 34 | SUFFIX ".mll") 35 | elseif(APPLE) 36 | set_target_properties(${PROJECT_NAME} PROPERTIES 37 | PREFIX "" 38 | SUFFIX ".bundle") 39 | else() 40 | set_target_properties(${PROJECT_NAME} PROPERTIES 41 | PREFIX "" 42 | SUFFIX ".so") 43 | endif() 44 | 45 | target_link_libraries(${PROJECT_NAME} ${MAYA_LIBRARIES}) 46 | 47 | if (WIN32) 48 | install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION plug-ins) 49 | else() 50 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION plug-ins) 51 | endif() 52 | # MAYA_PLUGIN(${PROJECT_NAME}) 53 | -------------------------------------------------------------------------------- /src/Renaming.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "Renaming.h" 26 | #include "UVCommon.h" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | using namespace boost; 36 | using namespace std; 37 | 38 | #define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 39 | 40 | Operation::Operation(const MString& newName, const MString& oldName, const MDagPath& path): 41 | m_newName(newName), 42 | m_oldName(oldName), 43 | m_path(path) 44 | { 45 | 46 | } 47 | 48 | Operation::Operation() 49 | { 50 | } 51 | 52 | void Operation::doIt() 53 | { 54 | MFnDependencyNode node(m_path.node()); 55 | node.setName(m_newName); 56 | } 57 | 58 | void Operation::undoIt() 59 | { 60 | MFnDependencyNode node(m_path.node()); 61 | node.setName(m_oldName); 62 | } 63 | 64 | //*************************************************************************************************************** 65 | 66 | TypeRename::TypeRename() 67 | { 68 | } 69 | 70 | TypeRename::~TypeRename() 71 | { 72 | } 73 | 74 | void* TypeRename::creator() 75 | { 76 | return new TypeRename; 77 | } 78 | 79 | bool TypeRename::isUndoable() const 80 | { 81 | return true; 82 | } 83 | 84 | // This command adds _GRP on groups and _GEO on geometry. 85 | 86 | MStatus TypeRename::doIt(const MArgList& args) 87 | { 88 | MStatus stat; 89 | 90 | bool dogrp = args.asString(0, &stat) == "grp";er; 91 | bool doply = args.asString(1, &stat) == "ply";er; 92 | bool dogeo = args.asString(1, &stat) == "geo";er; 93 | bool doall = args.asString(2, &stat) == "all";er; 94 | bool force = args.asBool(3, &stat) == true;er; 95 | 96 | MSelectionList list; 97 | 98 | m_operations.resize(0); 99 | 100 | MGlobal::getActiveSelectionList(list); 101 | 102 | { 103 | MItDag itdag(MItDag::kDepthFirst, MFn::kTransform, &stat);er 104 | 105 | MItSelectionList iter(list, MFn::kTransform); 106 | 107 | // For every group in the scene (depth first) 108 | while (dogrp && (doall ? !itdag.isDone() : !iter.isDone())) 109 | { 110 | MDagPath path; 111 | doall ? stat = itdag.getPath(path) : stat = iter.getDagPath(path);er 112 | 113 | MObject obj = path.node(&stat);er 114 | 115 | unsigned int childCount = path.childCount(&stat); 116 | 117 | bool transformIsGroup = childCount > 1; 118 | 119 | // if we only have one child and it happens to be a transform 120 | // then let's consider this a group too 121 | if (childCount == 1) 122 | { 123 | MObject child = path.child(0, &stat);er 124 | MFnTransform trans(child, &stat); 125 | if (stat == MS::kSuccess) 126 | transformIsGroup = true; 127 | } 128 | 129 | if (transformIsGroup) 130 | { 131 | MFnDependencyNode node(path.node(), &stat);er 132 | 133 | // get the name of the node 134 | string name = node.name().asChar(); 135 | 136 | // remove all those strings 137 | erase_all(name, "_GRP"); 138 | erase_all(name, "_GEO"); 139 | erase_all(name, "_PLY"); 140 | 141 | // name it as a group since it has more than one child 142 | Operation op((name + "_GRP").c_str(), node.name(), path); 143 | m_operations.push_back(op); 144 | } 145 | 146 | if (doall) 147 | { 148 | stat = itdag.next(); 149 | er 150 | } 151 | else 152 | { 153 | stat = iter.next(); 154 | er 155 | } 156 | } 157 | } 158 | 159 | { 160 | MItDag itdag = MItDag(MItDag::kDepthFirst, MFn::kMesh, &stat);er 161 | MItSelectionList sel(list, MFn::kMesh); 162 | 163 | int counter = 0; 164 | 165 | // Iterate over Meshes 166 | while ((doply || dogeo) && (doall ? !itdag.isDone() : !sel.isDone())) 167 | { 168 | MDagPath path; 169 | stat = doall ? itdag.getPath(path) : sel.getDagPath(path); 170 | path.pop(); 171 | 172 | MObject transformObj = path.transform(&stat);er 173 | 174 | MFnDependencyNode transformOfMeshNode(transformObj, &stat);er 175 | MFnDependencyNode meshNode(path.node(), &stat);er 176 | 177 | MString name = transformOfMeshNode.name(); 178 | std::string namestr = name.asChar(); 179 | 180 | bool isPly = std::string::npos != namestr.find("_PLY"); 181 | bool isGeo = std::string::npos != namestr.find("_GEO"); 182 | 183 | if (isGeo || isPly) 184 | { 185 | if (force) 186 | { 187 | string str(name.asChar()); 188 | erase_all(str, "_GEO"); 189 | erase_all(str, "_PLY"); 190 | name = str.c_str(); 191 | } 192 | else 193 | { 194 | doall ? itdag.next() : sel.next(); 195 | continue; 196 | } 197 | } 198 | 199 | MString newName; 200 | 201 | if (doply) 202 | newName = (name + "_PLY"); 203 | else if (dogeo) 204 | newName = (name + "_GEO"); 205 | 206 | Operation op(newName, transformOfMeshNode.name(), path); 207 | 208 | m_operations.push_back(op); 209 | 210 | doall ? itdag.next() : sel.next(); 211 | } 212 | } 213 | 214 | return redoIt(); 215 | } 216 | 217 | // UNDO THE COMMAND 218 | MStatus TypeRename::undoIt() 219 | { 220 | for (size_t i = 0; i < m_operations.size(); i++) 221 | m_operations[i].undoIt(); 222 | return MStatus(); 223 | } 224 | 225 | // REDO THE COMMAND 226 | MStatus TypeRename::redoIt() 227 | { 228 | for (size_t i = 0; i < m_operations.size(); i++) 229 | m_operations[i].doIt(); 230 | return MStatus(); 231 | } 232 | -------------------------------------------------------------------------------- /src/Renaming.h: -------------------------------------------------------------------------------- 1 | #ifndef _Renaming_H_ 2 | #define _Renaming_H_ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /*! This class represents an atomic rename operation 12 | * it does not perform any work other than the renaming itself 13 | */ 14 | struct Operation 15 | { 16 | /*! Public constructor 17 | * initialise this class by passing the objects new name, its old name, 18 | * and dag path towards the object you want to rename. 19 | */ 20 | Operation(const MString& newName, const MString& oldName, const MDagPath&); 21 | 22 | //! Default public destructor 23 | Operation(); 24 | 25 | //! Performs the node's duty 26 | void doIt(); 27 | 28 | //! Undo what was done in doit 29 | void undoIt(); 30 | 31 | //! The new name for the object 32 | MString m_newName; 33 | 34 | //! The old name for the object 35 | MString m_oldName; 36 | 37 | //! The path towards the object you want to rename 38 | MDagPath m_path; 39 | 40 | }; 41 | 42 | /*! This class takes care of renaming objects based on their type 43 | * There are 3 types of objects, GRP which contain transforms, PLY and GEO 44 | * which are transforms of polygons. Whether an object is PLY or GEO is 45 | * specified by the end user. 46 | */ 47 | class TypeRename : public MPxCommand 48 | { 49 | public: 50 | 51 | //!Default public constructor 52 | TypeRename(); 53 | 54 | //!Default public destructor 55 | virtual ~TypeRename(); 56 | 57 | //! Node creator 58 | static void* creator(); 59 | 60 | //! Specifies whether the action is undable 61 | bool isUndoable() const; 62 | 63 | //! Performs the node's duty 64 | MStatus doIt(const MArgList&); 65 | 66 | //! Undoes what was done in doIt 67 | MStatus undoIt(); 68 | 69 | //! Redoes what was undone, this function usually performs the actual work 70 | MStatus redoIt(); 71 | 72 | private: 73 | //! These are the rename operations which need to be performed 74 | std::vector m_operations; 75 | }; 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/UVCommon.cpp: -------------------------------------------------------------------------------- 1 | // "There is nothing noble in being superior to your fellow man; true nobility is being superior to your former self." 2 | // -Ernest Hemingway 3 | 4 | #include "UVCommon.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "assert.h" 15 | 16 | using namespace std; 17 | 18 | 19 | #define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 20 | 21 | UVCommon::UVCommon() 22 | { 23 | 24 | } 25 | 26 | UVCommon::~UVCommon() 27 | { 28 | 29 | } 30 | 31 | // This function creates a mesh representation of the UVs 32 | MObject UVCommon::getUVMesh(MFnMesh& fnMesh) 33 | { 34 | MStatus stat; 35 | int numUVs = fnMesh.numUVs(&stat);er 36 | 37 | MFloatArray uArray, vArray; 38 | 39 | stat = fnMesh.getUVs(uArray, vArray); 40 | 41 | MFloatPointArray vertices(uArray.length()); 42 | 43 | for (size_t i = 0; i < uArray.length(); i++) 44 | vertices[i] = MFloatPoint(uArray[i], 0, vArray[i]); 45 | 46 | MObject fnobj = fnMesh.object(&stat);er 47 | 48 | MItMeshPolygon itmesh(fnobj, &stat);er 49 | 50 | size_t numUVFaces = 0; 51 | 52 | MIntArray polygonCounts; 53 | 54 | MIntArray polygonConnects; 55 | 56 | size_t i = 0; 57 | for (itmesh.reset(); itmesh.isDone() == false; itmesh.next(), i++) 58 | { 59 | int polygonId = itmesh.index(&stat);er 60 | unsigned int vertexCount = itmesh.polygonVertexCount(&stat);er 61 | if (itmesh.hasUVs(&stat)) 62 | { 63 | er 64 | numUVFaces++; 65 | polygonCounts.append(0); 66 | for (size_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) 67 | { 68 | polygonCounts[i]++; 69 | int uvId; 70 | stat = fnMesh.getPolygonUVid(polygonId, vertexIndex, uvId);er 71 | polygonConnects.append(uvId); 72 | } 73 | } 74 | } 75 | 76 | MFnMesh uvMesh; 77 | 78 | MObject retObj = uvMesh.create(numUVs, numUVFaces, vertices, polygonCounts, polygonConnects, MObject::kNullObj, &stat);er 79 | 80 | return retObj; 81 | } 82 | 83 | // This function creates a different mesh for each UV shell 84 | // do not read unless you want subjected to an intense 85 | // headache followed by a severe brain hemorrhage 86 | MObjectArray UVCommon::getUVShells(MFnMesh& fnMesh) 87 | { 88 | MStatus stat; 89 | MIntArray uvShellIds; 90 | unsigned int nbUvShells; 91 | 92 | stat = fnMesh.getUvShellsIds(uvShellIds, nbUvShells);er 93 | 94 | MIntArray nbUvPerShell(nbUvShells); 95 | MIntArray UvsRemapped(uvShellIds.length()); 96 | 97 | for (size_t j = 0; j < uvShellIds.length(); j++) 98 | UvsRemapped[j] = nbUvPerShell[uvShellIds[j]]++; 99 | 100 | MObjectArray arr(nbUvShells); 101 | 102 | MFloatArray uArray, vArray; 103 | 104 | stat = fnMesh.getUVs(uArray, vArray); 105 | 106 | MObject fnobj = fnMesh.object(&stat);er 107 | 108 | MItMeshPolygon itmesh(fnobj, &stat);er 109 | 110 | vector numUVFaces(nbUvShells); 111 | vector polygonCounts(nbUvShells); 112 | vector polygonConnects(nbUvShells); 113 | vector vertices(nbUvShells); 114 | 115 | for (size_t i = 0; i < uArray.length(); i++) 116 | vertices[uvShellIds[i]].append(MFloatPoint(uArray[i], 0, vArray[i])); 117 | 118 | for (itmesh.reset(); itmesh.isDone() == false; itmesh.next()) 119 | { 120 | int polygonId = itmesh.index(&stat);er 121 | unsigned int vertexCount = itmesh.polygonVertexCount(&stat);er 122 | assert(vertexCount); 123 | if (itmesh.hasUVs(&stat)) 124 | { 125 | er 126 | double area; 127 | itmesh.getUVArea(area); 128 | int uvId; 129 | stat = fnMesh.getPolygonUVid(polygonId, 0, uvId);er 130 | numUVFaces[uvShellIds[uvId]]++; 131 | polygonCounts[uvShellIds[uvId]].append(0); 132 | for (size_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) 133 | { 134 | polygonCounts[uvShellIds[uvId]][polygonCounts[uvShellIds[uvId]].length()-1]++; 135 | stat = fnMesh.getPolygonUVid(polygonId, vertexIndex, uvId);er 136 | polygonConnects[uvShellIds[uvId]].append(UvsRemapped[uvId]); 137 | } 138 | } 139 | } 140 | 141 | MFnMesh uvMesh; 142 | 143 | for (size_t j = 0; j < nbUvShells; j++) 144 | arr[j] = uvMesh.create(nbUvPerShell[j], numUVFaces[j], vertices[j], polygonCounts[j], polygonConnects[j], MObject::kNullObj, &stat);er 145 | 146 | return arr; 147 | } 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /src/UVCommon.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_COMMON_H_ 2 | #define _UV_COMMON_H_ 3 | 4 | #include 5 | #include 6 | 7 | class MFnMesh; 8 | 9 | //! This class provides common functionality for UV classes in the codebase 10 | class UVCommon 11 | { 12 | public: 13 | //! Default public constructor 14 | UVCommon(); 15 | 16 | //! Default public destructor 17 | ~UVCommon(); 18 | 19 | /*! Given an MFnMesh, create a new MFnMesh representation of the UVs 20 | * The resulting mesh created by this function is the exact 21 | * polygon representation of the UVs as seen in the UV editor 22 | * turning UVs into polygons enables us to perform work on UVs 23 | * while using algorithms reserved to polys 24 | */ 25 | static MObject getUVMesh(MFnMesh& mesh); 26 | 27 | /*! Given an MFnMesh, extract all UV Shells into an object array 28 | * This function has to exist because the UV set of a polygon object 29 | * can be formed of more than a single shell. 30 | */ 31 | static MObjectArray getUVShells(MFnMesh& mesh); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/UVReversed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "UVReversed.h" 23 | #include "UVCommon.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | //#define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 30 | #define er ; 31 | 32 | using namespace std; 33 | 34 | #define MERR_CHK(stat,msg) if ( !stat ) { MGlobal::displayError(msg); } // cerr << msg << endl; } 35 | 36 | UVReversed::UVReversed() 37 | { 38 | } 39 | 40 | UVReversed::~UVReversed() 41 | { 42 | } 43 | 44 | void* UVReversed::creator() 45 | { 46 | return new UVReversed; 47 | } 48 | 49 | bool UVReversed::isUndoable() const 50 | { 51 | return false; 52 | } 53 | 54 | MStatus UVReversed::doIt(const MArgList& args) 55 | { 56 | MStatus stat; 57 | 58 | MString meshName = args.asString(0, &stat);er 59 | MSelectionList list; 60 | list.add(meshName); 61 | MDagPath path; 62 | stat = list.getDagPath(0, path);er 63 | MFnMesh fnMesh(path, &stat);er 64 | 65 | MObject obj = UVCommon::getUVMesh(fnMesh); 66 | 67 | // go over every vertex 68 | MItMeshPolygon itmeshp(obj, &stat);er 69 | MItMeshPolygon itmeshp2(path.node(), &stat);er 70 | 71 | MSelectionList selection; 72 | 73 | bool inversionFound = false; 74 | 75 | MIntArray reversedUVs; 76 | 77 | for (itmeshp.reset(); itmeshp.isDone() == false; itmeshp.next()) 78 | { 79 | MVector normal; 80 | stat = itmeshp.getNormal(normal, MSpace::kWorld); 81 | cout << "normal " << normal.y << endl; 82 | if (normal.y > 0) 83 | { 84 | inversionFound = true; 85 | int prev = 0; 86 | itmeshp2.setIndex(itmeshp.index(), prev); 87 | if (itmeshp2.hasUVs()) 88 | { 89 | // get number of verts 90 | MIntArray vertices; 91 | stat = itmeshp2.getVertices(vertices);er 92 | // for each vert 93 | for (size_t i = 0; i < vertices.length(); i++) 94 | { 95 | // get UV 96 | int index; 97 | stat = itmeshp2.getUVIndex(i,index); 98 | // add UV to list 99 | reversedUVs.append(index); 100 | } 101 | } 102 | } 103 | } 104 | 105 | setResult(inversionFound); 106 | 107 | if (inversionFound) 108 | { 109 | MString str = "select -add "; 110 | for (size_t i = 0; i < reversedUVs.length(); i++) 111 | { 112 | str += meshName + ".map[" + reversedUVs[i] + "] "; 113 | } 114 | cout << str << endl; 115 | MGlobal::executeCommand(str); 116 | } 117 | 118 | stat = MGlobal::deleteNode( obj );er 119 | 120 | return stat; 121 | } 122 | 123 | // UNDO THE COMMAND 124 | MStatus UVReversed::undoIt() 125 | { 126 | return MStatus(); 127 | } 128 | -------------------------------------------------------------------------------- /src/UVReversed.h: -------------------------------------------------------------------------------- 1 | #ifndef _UVReversed_H_ 2 | #define _UVReversed_H_ 3 | 4 | #include 5 | #include 6 | 7 | class UVReversed : public MPxCommand 8 | { 9 | public: 10 | //! Default public constructor 11 | UVReversed(); 12 | 13 | //! Default public destructor 14 | virtual ~UVReversed(); 15 | 16 | //! Node creator 17 | static void* creator(); 18 | 19 | //! Specifies whether the action is undable 20 | bool isUndoable() const; 21 | 22 | //! Performs the node's duty 23 | MStatus doIt(const MArgList&); 24 | 25 | //! Undoes what was done in doIt 26 | MStatus undoIt(); 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/UVSeams.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "UVSeams.h" 23 | #include "UVCommon.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | //#define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 30 | #define er ; 31 | 32 | using namespace std; 33 | 34 | #define MERR_CHK(stat,msg) if ( !stat ) { MGlobal::displayError(msg); } // cerr << msg << endl; } 35 | 36 | UVSeams::UVSeams() 37 | { 38 | } 39 | 40 | UVSeams::~UVSeams() 41 | { 42 | } 43 | 44 | void* UVSeams::creator() 45 | { 46 | return new UVSeams; 47 | } 48 | 49 | bool UVSeams::isUndoable() const 50 | { 51 | return false; 52 | } 53 | 54 | MStatus UVSeams::doIt(const MArgList& args) 55 | { 56 | MStatus stat; 57 | 58 | MString meshName = args.asString(0, &stat);er 59 | MSelectionList list; 60 | list.add(meshName); 61 | MDagPath path; 62 | stat = list.getDagPath(0, path);er 63 | MFnMesh fnMesh(path, &stat);er 64 | 65 | MObject obj = UVCommon::getUVMesh(fnMesh); 66 | 67 | // go over every vertex 68 | MItMeshVertex itmeshv(obj, &stat);er 69 | MItMeshVertex itmeshv2(obj, &stat);er 70 | MItMeshEdge itmeshe(obj, &stat);er 71 | 72 | MSelectionList selection; 73 | 74 | bool seamFound = false; 75 | 76 | MIntArray seamVerts; 77 | 78 | for (itmeshv.reset(); itmeshv.isDone() == false; itmeshv.next()) 79 | { 80 | MIntArray edgeList; 81 | // for each vertex get ever edge 82 | stat = itmeshv.getConnectedEdges(edgeList); 83 | 84 | int vertexIndex = itmeshv.index(); 85 | 86 | // if neighbouring edge has dot prod of circa 1 that's most likely a seam 87 | for (size_t i = 0; i < edgeList.length(); i++) 88 | { 89 | int e1 = edgeList[i]; 90 | int e2 = edgeList[i < edgeList.length()-1 ? i + 1 : 0]; 91 | 92 | int oppVertex1; 93 | int oppVertex2; 94 | 95 | int prevIndex = 0; 96 | 97 | stat = itmeshv.getOppositeVertex(oppVertex1, e1);er 98 | 99 | MPoint e1v0 = itmeshv.position(MSpace::kObject,&stat);er 100 | 101 | stat = itmeshv2.setIndex(oppVertex1, prevIndex);er 102 | 103 | MPoint e1v1 = itmeshv2.position(MSpace::kObject,&stat);er 104 | 105 | MVector e1e(e1v1 - e1v0); 106 | 107 | stat = itmeshv.getOppositeVertex(oppVertex2, e2);er 108 | 109 | stat = itmeshv2.setIndex(oppVertex2, prevIndex);er 110 | 111 | MPoint e2v1 = itmeshv2.position(MSpace::kObject,&stat);er 112 | 113 | MVector e2e(e2v1 - e1v0); 114 | 115 | if ((e1e.normal() * e2e.normal() > 0.999) && fabs(e1e.length() - e2e.length()) < 0.001) 116 | { 117 | seamVerts.append(vertexIndex); 118 | seamVerts.append(oppVertex1); 119 | seamVerts.append(oppVertex2); 120 | seamFound = true; 121 | } 122 | if (edgeList.length() == 2) 123 | break; 124 | } 125 | } 126 | 127 | setResult(seamFound); 128 | 129 | if (seamFound) 130 | { 131 | MString str = "select -add "; 132 | for (size_t i = 0; i < seamVerts.length(); i++) 133 | { 134 | str += meshName + ".map[" + seamVerts[i] + "] "; 135 | } 136 | MGlobal::executeCommand(str); 137 | } 138 | 139 | 140 | stat = MGlobal::deleteNode( obj );er 141 | 142 | return stat; 143 | } 144 | 145 | // UNDO THE COMMAND 146 | MStatus UVSeams::undoIt() 147 | { 148 | return MStatus(); 149 | } 150 | -------------------------------------------------------------------------------- /src/UVSeams.h: -------------------------------------------------------------------------------- 1 | #ifndef _UVSEAMS_H_ 2 | #define _UVSEAMS_H_ 3 | 4 | #include 5 | #include 6 | 7 | /*! Find seams in the default UV set of the given mesh. 8 | * Seams are when two UV edges are perfectly aligned (with a dot product of =~ 1) 9 | * and share a vertex 10 | */ 11 | class UVSeams : public MPxCommand 12 | { 13 | public: 14 | //! Default public constructor 15 | UVSeams(); 16 | 17 | //! Default public destructor 18 | virtual ~UVSeams(); 19 | 20 | 21 | //! Node creator 22 | static void* creator(); 23 | 24 | //! Specifies whether the action is undable 25 | bool isUndoable() const; 26 | 27 | //! Performs the node's duty 28 | MStatus doIt(const MArgList&); 29 | 30 | //! Undoes what was done in doIt 31 | MStatus undoIt(); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/holesBorder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "holesBorder.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 32 | 33 | using namespace std; 34 | 35 | /* ______________ 36 | ,===:'., `-._ 37 | `:.`---.__ `-._ 38 | `:. `--. `. 39 | \. `. `. 40 | (,,(, \. `. ____,-`., 41 | (,' `/ \. ,--.___`.' 42 | , ,' ,--. `, \.;' ` 43 | `{D, { \ : \; 44 | V,,' / / // 45 | j;; / ,' ,-//. ,---. , 46 | \;' / ,' / _ \ / _ \ ,'/ 47 | \ `' / \ `' / \ `.' / 48 | `.___,' `.__,' `.__,' 49 | 50 | 51 | Right so this check's aim is to fix holes within polygonal geometry by adding an extra edge 52 | loop within a specified threshold of said hole. As a result, the hole keeps its shape when the 53 | geometry is smoothed or converted to subDs. 54 | 55 | Now maya can already do a lot of the preliminary work by selecting the edges which are on the 56 | boundary, with: 57 | 58 | polySelectConstraint -m 3 -t 0x8000 -w 1; 59 | polySelectConstraint -dis; 60 | 61 | It's at this point that this plugin command gets invoked. So our input is just the assumption 62 | that the current selection holds boundary edges. These could represent one or more holes, on 63 | more than one object. 64 | 65 | The first step is therefore to run an algorithm to sort this set of edges into individual sets, 66 | with each set representing one hole, basically turning S into discreet sets of ordered edges. 67 | 68 | We do this by running a recursive algorithm which picks the first edge within our input set S 69 | and *walks* along that edge to the next contiguous edge which is on a boundary. Each time such 70 | an edge is encoutered it is removed from S and added to its own respective ordered set. The 71 | algorithm continues recursing until it hits an edge which is within our new ordered set at 72 | which point we have walked around the entire hole. 73 | 74 | At this point it returns to the first edge in S and starts recursing once again. The algorithm 75 | continues doing this until S is empty. 76 | 77 | std::find being linear my estimate is that this algorithm also runs in linear time according 78 | to the number of edges in S. 79 | 80 | */ 81 | 82 | holesBorder::holesBorder() 83 | { 84 | } 85 | 86 | holesBorder::~holesBorder() 87 | { 88 | } 89 | 90 | void* holesBorder::creator() 91 | { 92 | return new holesBorder; 93 | } 94 | 95 | bool holesBorder::isUndoable() const 96 | { 97 | return false; 98 | } 99 | 100 | // here we assume that we have a bunch of border edges selected 101 | // in one mesh only 102 | MStatus holesBorder::doIt(const MArgList& args) 103 | { 104 | // Even though we have edges selected, getActiveSelectionList only returns 105 | // objects, not components 106 | MSelectionList list; 107 | MStatus stat = MGlobal::getActiveSelectionList(list);er 108 | 109 | MString returnStr; 110 | 111 | // for now we'll only work with one object at a time.. else 112 | // it will get too messy 113 | 114 | for (size_t i = 0; i < list.length(); i++) 115 | { 116 | // This is the threshold 117 | // if we are below this threshold then do not insert loops 118 | // although this threshold is in world space which sucks 119 | float threshold = 0.1; 120 | 121 | MDagPath path; 122 | MObject component; 123 | stat = list.getDagPath(i,path,component);er 124 | MFnMesh mesh(path, &stat);er 125 | MString name = path.fullPathName(&stat);er 126 | MItMeshEdge ite(path, component, &stat);er 127 | MItMeshVertex itv(path, MObject::kNullObj, &stat);er 128 | int prevIndex = 0; 129 | 130 | std::list allBorderEdges; 131 | vector > borders; 132 | vector > rings; 133 | 134 | while (!ite.isDone()) 135 | { 136 | allBorderEdges.push_back(ite.index(&stat));er 137 | ite.next(); 138 | } 139 | 140 | std::list::iterator itel = allBorderEdges.begin(); 141 | 142 | uint holeNumber = 0; 143 | 144 | int counter = 0; 145 | 146 | // sort all the edges into descreet buckets of contiguous edgess 147 | while (itel != allBorderEdges.end() && counter++ < 500) 148 | { 149 | // so we have our first edge 150 | uint edge = *itel; 151 | 152 | // let's pick a vertex fairly randomly 153 | int vertexList[2]; 154 | stat = mesh.getEdgeVertices(edge, vertexList);er 155 | 156 | // set it as the start index of the vertex iterator 157 | stat = itv.setIndex(vertexList[1], prevIndex);er 158 | 159 | rings.push_back(vector()); 160 | borders.push_back(vector()); 161 | func(edge, vertexList[1], mesh, ite, itv, holeNumber++, borders, rings, allBorderEdges, itel); 162 | } 163 | 164 | bool splitDone = false; 165 | 166 | for (size_t i = 0; i < borders.size() && splitDone == false; i++) 167 | { 168 | vector edgeLength(rings[i].size()); 169 | for (size_t j = 0; j < rings[i].size(); j++) 170 | { 171 | ite.setIndex(rings[i][j].m_edge, prevIndex); 172 | stat = ite.getLength(edgeLength[j], MSpace::kWorld);er 173 | } 174 | 175 | auto const maxDist = max_element(edgeLength.begin(), edgeLength.end()); 176 | 177 | if ((maxDist != edgeLength.end()) && (fabs(*maxDist - threshold) > 0.05)) 178 | { 179 | stringstream ss; 180 | ss << "polySplit "; 181 | 182 | for (size_t j = 0; j < rings[i].size(); j++) 183 | { 184 | int vertexList[2]; 185 | stat = mesh.getEdgeVertices(rings[i][j].m_edge, vertexList);er 186 | 187 | float f = 0.1/edgeLength[j]; 188 | if (f > 1 || f < 0) f = 0.5; 189 | uint boundaryVertex = rings[i][j].m_boundaryVertex; 190 | uint internalVertex = rings[i][j].m_internalVertex; 191 | 192 | float inv = ((boundaryVertex == vertexList[0]) ? f : 1-f); 193 | 194 | assert(inv >= 0 && inv <= 1); 195 | 196 | ss << " -ep " << rings[i][j].m_edge << " " << inv; 197 | } 198 | 199 | int vertexList[2]; 200 | stat = mesh.getEdgeVertices(rings[i][0].m_edge, vertexList);er 201 | float f = 0.1/edgeLength[0]; 202 | if (f > 1 || f < 0) f = 0.5; 203 | float inv = rings[i][0].m_boundaryVertex == vertexList[0] ? f : 1-f; 204 | assert(inv >= 0 && inv <= 1); 205 | ss << " -ep " << rings[i][0].m_edge << " " << inv << " " << path.fullPathName().asChar() << "; "; 206 | 207 | returnStr += MString(ss.str().c_str()); 208 | 209 | splitDone = true; 210 | } 211 | } 212 | } 213 | MPxCommand::setResult(returnStr); 214 | return MS::kSuccess; 215 | } 216 | 217 | // Recursive function for sorting polygonal edges into 218 | // discreet sets of connected edges 219 | MStatus holesBorder::func( uint edge, 220 | uint vertex, 221 | const MFnMesh& mesh, 222 | MItMeshEdge& ite, 223 | MItMeshVertex& itv, 224 | uint holeNumber, 225 | vector >& borders, 226 | vector >& rings, 227 | std::list& allBorderEdges, 228 | std::list::iterator& itel 229 | ) 230 | { 231 | MStatus stat; 232 | int prevIndex = 0; 233 | stat = itv.setIndex(vertex, prevIndex); 234 | 235 | // get edges connected to current vertex 236 | MIntArray edgesConnectedToVertex; 237 | stat = itv.getConnectedEdges(edgesConnectedToVertex); 238 | 239 | // for each connected edge 240 | for (size_t j = 0; j < edgesConnectedToVertex.length(); j++) 241 | { 242 | // that is not the current edge 243 | if ((uint)edgesConnectedToVertex[j] != edge) 244 | { 245 | // get vertices of this connected edge 246 | int vertexList[2]; 247 | stat = mesh.getEdgeVertices(edgesConnectedToVertex[j], vertexList);er 248 | stat = ite.setIndex(edgesConnectedToVertex[j], prevIndex);er 249 | 250 | // if that particular edge is on the boundary 251 | if (ite.onBoundary(&stat)) 252 | { 253 | er 254 | // add that edge to its appropriate bucket 255 | borders[holeNumber].push_back(edge); 256 | 257 | // remove from the pool 258 | allBorderEdges.remove(edge); 259 | 260 | itel = allBorderEdges.begin(); 261 | 262 | // look for this edge in the bucket.. 263 | vector::iterator fit = find(borders[holeNumber].begin(), borders[holeNumber].end(), edgesConnectedToVertex[j]); 264 | 265 | // if it's in there in means we've gone all 266 | // around the loop so we can stop 267 | if (fit == borders[holeNumber].end()) 268 | // else recurse 269 | func((uint)edgesConnectedToVertex[j], vertex == vertexList[0] ? (uint)vertexList[1] : (uint)vertexList[0], mesh, ite, itv, holeNumber, borders, rings, allBorderEdges, itel); 270 | } 271 | else 272 | { 273 | // if the edge is not on a boundary it means it's one of the edges 274 | // that will need splitting.. so store its information 275 | RingEdgeInfo info = { 276 | // Edge 277 | (uint)edgesConnectedToVertex[j], 278 | // Boundary Vertex 279 | (uint)vertex, 280 | // Internal Vertex 281 | (uint)(vertex == vertexList[0] ? vertexList[1] : vertexList[0]) 282 | }; 283 | rings[holeNumber].push_back(info); 284 | } 285 | } 286 | } 287 | return MS::kSuccess; 288 | } 289 | 290 | MStatus holesBorder::undoIt() 291 | { 292 | return MStatus(); 293 | } 294 | -------------------------------------------------------------------------------- /src/holesBorder.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOLES_BORDER_H_ 2 | #define _HOLES_BORDER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | typedef unsigned int uint; 16 | 17 | //! Find holes in a mesh and create a split around said hole 18 | class holesBorder : public MPxCommand 19 | { 20 | 21 | struct RingEdgeInfo 22 | { 23 | uint m_edge; 24 | uint m_boundaryVertex; 25 | uint m_internalVertex; 26 | }; 27 | 28 | public: 29 | //! Default public constructor 30 | holesBorder(); 31 | 32 | //! Default public destructor 33 | virtual ~holesBorder(); 34 | 35 | //! Node creator 36 | static void* creator(); 37 | 38 | //! Specifies whether the action is undable 39 | bool isUndoable() const; 40 | 41 | //! Performs the node's duty 42 | MStatus doIt(const MArgList&); 43 | 44 | //! Undoes what was done in doIt 45 | MStatus undoIt(); 46 | 47 | 48 | /*! recursive function which does the main part of the algorithm's work 49 | */ 50 | MStatus func( uint edge, 51 | uint vertex, 52 | const MFnMesh&, 53 | MItMeshEdge&, 54 | MItMeshVertex& itv, 55 | uint hole, 56 | std::vector >& borders, 57 | std::vector >& rings, 58 | std::list& allBorderEdges, 59 | std::list::iterator& itel); 60 | 61 | 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/intersect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "intersect.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 28 | 29 | using namespace std; 30 | 31 | #ifndef INTERSECTCMD 32 | #define INTERSECTCMD 33 | 34 | #define MERR_CHK(stat,msg) if ( !stat ) { MGlobal::displayError(msg); } // cerr << msg << endl; } 35 | 36 | #endif 37 | 38 | checkNormalDirection::checkNormalDirection() 39 | { 40 | } 41 | 42 | checkNormalDirection::~checkNormalDirection() 43 | { 44 | } 45 | 46 | void* checkNormalDirection::creator() 47 | { 48 | return new checkNormalDirection; 49 | } 50 | 51 | bool checkNormalDirection::isUndoable() const 52 | { 53 | return false; 54 | } 55 | 56 | MStatus checkNormalDirection::doIt(const MArgList& args) 57 | { 58 | float pa, pb; 59 | NormalDirection normalDira, normalDirb; 60 | 61 | methodA(normalDira, pa, args); 62 | methodB(normalDirb, pb, args); 63 | 64 | if (pa >= pb && normalDira == eOUTWARDS) 65 | { 66 | setResult("outwards"); 67 | } 68 | else if (pa >= pb && normalDira == eINWARDS) 69 | { 70 | setResult("inwards"); 71 | } 72 | if (pa < pb && normalDirb == eOUTWARDS) 73 | { 74 | setResult("outwards"); 75 | } 76 | else if (pa < pb && normalDirb == eINWARDS) 77 | { 78 | setResult("inwards"); 79 | } 80 | return MS::kSuccess; 81 | } 82 | 83 | // UNDO THE COMMAND 84 | MStatus checkNormalDirection::undoIt() 85 | { 86 | return MStatus(); 87 | } 88 | 89 | MStatus checkNormalDirection::methodB(NormalDirection& normalDir, float& p, const MArgList& args) 90 | { 91 | MStatus stat = MStatus::kSuccess; 92 | 93 | if (args.length() < 2) 94 | { 95 | 96 | stringstream ss; 97 | ss << "Need name of the mesh and the number of faces that you want to inspect." << endl; 98 | ss << "num args given " << args.length() << endl; 99 | 100 | MGlobal::displayError(MString(string(ss.str()).c_str())); 101 | return MStatus::kFailure; 102 | } 103 | 104 | MString meshName = args.asString(0, &stat);er 105 | int numFacesToInspect = args.asInt(1, &stat);er 106 | 107 | MSelectionList list; 108 | list.add(meshName); 109 | MDagPath path; 110 | stat = list.getDagPath(0, path);er 111 | MFnMesh fnMesh(path, &stat);er 112 | 113 | MMeshIsectAccelParams mmAccelParams = fnMesh.autoUniformGridParams(); 114 | 115 | int numCollisions = 0; 116 | 117 | int numfaces = fnMesh.numPolygons(&stat);er 118 | 119 | MItMeshPolygon itmesh(path, MObject::kNullObj, &stat);er 120 | 121 | int numPairIntersections = 0; 122 | 123 | MFloatVector normal; 124 | MVector vec; 125 | MFloatPoint center; 126 | 127 | int skipFactor = numfaces/numFacesToInspect; 128 | size_t i = 0; 129 | 130 | int numChecksPerformed = 0; 131 | 132 | for (itmesh.reset(); itmesh.isDone() == false; itmesh.next(), i++) 133 | { 134 | if (skipFactor > 1 && i % skipFactor != 0) 135 | continue; 136 | stat = itmesh.getNormal(vec,MSpace::kObject); 137 | normal = vec; 138 | center = MFloatPoint(itmesh.center(MSpace::kObject, &stat));er 139 | // nudge starting position so we don't self intersect 140 | center += normal*0.01; 141 | stat = intersectVectorWithMesh(numCollisions, center, normal, fnMesh, mmAccelParams); 142 | if (numCollisions%2 == 0) numPairIntersections++; 143 | numChecksPerformed++; 144 | } 145 | 146 | float dirp = numPairIntersections/(float)numChecksPerformed; 147 | 148 | if (dirp >= .5) 149 | { 150 | p = (numPairIntersections/(float)numChecksPerformed-0.5)*2.0; 151 | normalDir = eOUTWARDS; 152 | } 153 | else 154 | { 155 | p = ((numChecksPerformed-numPairIntersections)/(float)numChecksPerformed-0.5)*2.0; 156 | normalDir = eINWARDS; 157 | } 158 | 159 | return stat; 160 | } 161 | 162 | MStatus checkNormalDirection::methodA(NormalDirection& normalDir, float& p, const MArgList& args) 163 | { 164 | MStatus stat = MStatus::kSuccess; 165 | 166 | if (args.length() < 2) 167 | { 168 | MGlobal::displayError("Need name of the mesh and the number of faces that you want to inspect"); 169 | return MStatus::kFailure; 170 | } 171 | 172 | MString meshName = args.asString(0, &stat);er 173 | int numFacesToInspect = args.asInt(1, &stat);er 174 | 175 | MSelectionList list; 176 | list.add(meshName); 177 | MDagPath path; 178 | stat = list.getDagPath(0, path);er 179 | MFnMesh fnMesh(path, &stat);er 180 | 181 | MMeshIsectAccelParams mmAccelParams = fnMesh.autoUniformGridParams(); 182 | 183 | int numfaces = fnMesh.numPolygons(&stat);er 184 | 185 | if (numfaces <= 2) 186 | { 187 | setResult("NA"); 188 | return MS::kFailure; 189 | } 190 | 191 | MItMeshPolygon itmesh(path, MObject::kNullObj, &stat);er 192 | MItMeshPolygon itmesh2(path, MObject::kNullObj, &stat);er 193 | MItMeshVertex itmeshvtx(path, MObject::kNullObj, &stat);er 194 | MBoundingBox bbox; 195 | 196 | for (itmeshvtx.reset(); itmeshvtx.isDone() == false; itmeshvtx.next()) 197 | bbox.expand(itmeshvtx.position(MSpace::kWorld)); 198 | 199 | MVector normal; 200 | MVector vec; 201 | MFloatPoint center; 202 | MFloatPoint rayPos; 203 | 204 | int numChecksPerformed = 0; 205 | 206 | srand(0); 207 | 208 | int outwardCount = 0; 209 | 210 | size_t counterc = 0; 211 | 212 | while (numChecksPerformed < numFacesToInspect) 213 | { 214 | if (counterc++ >= 5000) 215 | break; 216 | 217 | bool collided = false; 218 | 219 | center.x = bbox.center().x; 220 | center.y = bbox.center().y; 221 | center.z = bbox.center().z; 222 | 223 | int counter = 0; 224 | // generate random point as the origine of the ray, piont that is definitely outside the bounding box 225 | do 226 | { 227 | rayPos.x = bbox.center().x+((rand()/(float)RAND_MAX)-0.5)*bbox.width()*2; 228 | rayPos.y = bbox.center().y+((rand()/(float)RAND_MAX)-0.5)*bbox.height()*2; 229 | rayPos.z = bbox.center().z+((rand()/(float)RAND_MAX)-0.5)*bbox.depth()*2; 230 | }while(bbox.contains(rayPos) && counter++ < 500); 231 | 232 | MFloatVector ray = center-rayPos; 233 | 234 | // drawVector(rayPos, ray); 235 | 236 | MFloatPoint collisionPos; 237 | 238 | float fHitRayParam, fHitBary1, fHitBary2; 239 | int nHitFace, nHitTriangle; 240 | 241 | // a large positive number is used here for the maxParam parameter 242 | collided = fnMesh.closestIntersection(rayPos, ray, NULL, NULL, false, MSpace::kWorld, (float)1, false, &mmAccelParams, collisionPos, &fHitRayParam, &nHitFace, &nHitTriangle, &fHitBary1, &fHitBary2, (float)1e-6, &stat); 243 | 244 | // it *should* collide, but if for some mysterious reason 245 | // it doesn't then it's no big deal... this is the maya API after all 246 | if (!collided) 247 | continue; 248 | 249 | // polySphere(collisionPos); 250 | 251 | int pv = nHitFace > 0 ? nHitFace-1 : 1; 252 | itmesh2.setIndex(nHitFace, pv); 253 | itmesh2.getNormal(normal); 254 | 255 | // get dot product with ray 256 | 257 | ray.normalize(); 258 | normal.normalize(); 259 | 260 | double dot = normal * ray; 261 | 262 | if (dot < 0) 263 | outwardCount++; 264 | 265 | numChecksPerformed++; 266 | } 267 | 268 | if (outwardCount > numChecksPerformed / 2) 269 | { 270 | p = (outwardCount/(float)numChecksPerformed-0.5)*2.0; 271 | normalDir = eOUTWARDS; 272 | } 273 | else 274 | { 275 | p = ((numChecksPerformed-outwardCount)/(float)numChecksPerformed-0.5)*2.0; 276 | normalDir = eINWARDS; 277 | } 278 | 279 | return stat; 280 | } 281 | 282 | MStatus checkNormalDirection::intersectVectorWithMesh(int& nNumberHitPoints, const MFloatPoint& pos, const MFloatVector& dir, MFnMesh& fnMesh, MMeshIsectAccelParams& mmAccelParams) 283 | { 284 | MStatus stat = MStatus::kSuccess; 285 | 286 | nNumberHitPoints = 0; 287 | 288 | static MFloatPoint hitPoint; 289 | 290 | static float fHitRayParam, fHitBary1, fHitBary2; 291 | static int nHitFace, nHitTriangle; 292 | 293 | // a large positive number is used here for the maxParam parameter 294 | static bool bAnyIntersection; 295 | bAnyIntersection = fnMesh.anyIntersection(pos, dir, NULL, NULL, false, MSpace::kObject, (float)9999, false, &mmAccelParams, hitPoint, &fHitRayParam, &nHitFace, &nHitTriangle, &fHitBary1, &fHitBary2, (float)1e-6, &stat); 296 | 297 | if (! bAnyIntersection) 298 | { 299 | return stat; 300 | } 301 | 302 | static MFloatPointArray hitPoints; 303 | static MFloatArray faHitRayParams; 304 | static MIntArray iaHitFaces; 305 | static MIntArray iaHitTriangles; 306 | static MFloatArray faHitBary1; 307 | static MFloatArray faHitBary2; 308 | 309 | static bool bAllIntersections; 310 | bAllIntersections = fnMesh.allIntersections(pos, dir, NULL, NULL, false, MSpace::kObject, 9999, false, NULL, false, hitPoints, &faHitRayParams, &iaHitFaces, &iaHitTriangles, &faHitBary1, &faHitBary2, 0.000001f, &stat); 311 | 312 | if (! bAllIntersections) 313 | { 314 | return stat; 315 | } 316 | 317 | // check how many intersections are found 318 | nNumberHitPoints = hitPoints.length(); 319 | 320 | return stat; 321 | } 322 | -------------------------------------------------------------------------------- /src/intersect.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTERSECT_H_ 2 | #define _INTERSECT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //! This class represents the plugin to check whether an mesh is inside out or outside in 11 | class checkNormalDirection : public MPxCommand 12 | { 13 | public: 14 | //! Default public constructor 15 | checkNormalDirection(); 16 | 17 | //! Default public destructor 18 | virtual ~checkNormalDirection(); 19 | 20 | //! Node creator 21 | static void* creator(); 22 | 23 | //! Specifies whether the action is undable 24 | bool isUndoable() const; 25 | 26 | //! Performs the node's duty 27 | MStatus doIt(const MArgList&); 28 | 29 | //! Undoes what was done in doIt 30 | MStatus undoIt(); 31 | 32 | private: 33 | 34 | //! This function encapsulates the fast intersection of a vector with a mesh 35 | MStatus intersectVectorWithMesh( 36 | int& nNumberHitPoints, 37 | const MFloatPoint& pos, 38 | const MFloatVector& dir, 39 | MFnMesh& fnMesh, 40 | MMeshIsectAccelParams& mmAccelParams 41 | ); 42 | 43 | //! Enumerates whether a normal is facing inwards or outwards 44 | enum NormalDirection 45 | { 46 | eINWARDS, 47 | eOUTWARDS 48 | }; 49 | 50 | //! Randomly shoots rays from outside the object towards its centre, computes direction of normals as a probability 51 | MStatus methodA(NormalDirection& normalDir, float& p, const MArgList& args); 52 | //! Shoots rays off each normal and counts how many times it penetrates the object, based on this computers the direction of normals as a probability 53 | MStatus methodB(NormalDirection& normalDir, float& p, const MArgList& args); 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/overlappingUVShells.cpp: -------------------------------------------------------------------------------- 1 | // "When I was 5 years old my mother always told me that happiness was the key to life. 2 | // When I went to school, they asked me what I wanted to be when i grew up. I wrote down "Happy". 3 | // They told me i didnt understand the assignment, and I told them they didnt understand life." - John Lennon 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "UVCommon.h" 28 | 29 | #include "overlappingUVShells.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "string.h" 38 | 39 | #define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 40 | #define err if (stat != MS::kSuccess) {cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; return MS::kFailure;} 41 | //#define er ; 42 | 43 | using namespace std; 44 | 45 | #define MERR_CHK(stat,msg) if ( !stat ) { MGlobal::displayError(msg); } // cerr << msg << endl; } 46 | 47 | OverlappingUVShells::OverlappingUVShells() 48 | { 49 | } 50 | 51 | OverlappingUVShells::~OverlappingUVShells() 52 | { 53 | } 54 | 55 | void* OverlappingUVShells::creator() 56 | { 57 | return new OverlappingUVShells; 58 | } 59 | 60 | bool OverlappingUVShells::isUndoable() const 61 | { 62 | return false; 63 | } 64 | 65 | int tri_tri_overlap_test_3d(double p1[3], double q1[3], double r1[3], 66 | double p2[3], double q2[3], double r2[3]); 67 | 68 | 69 | int coplanar_tri_tri3d(double p1[3], double q1[3], double r1[3], 70 | double p2[3], double q2[3], double r2[3], 71 | double N1[3], double N2[3]); 72 | 73 | 74 | int tri_tri_overlap_test_2d(double p1[2], double q1[2], double r1[2], 75 | double p2[2], double q2[2], double r2[2]); 76 | 77 | 78 | int tri_tri_intersection_test_3d(double p1[3], double q1[3], double r1[3], 79 | double p2[3], double q2[3], double r2[3], 80 | int * coplanar, 81 | double source[3],double target[3]); 82 | 83 | 84 | struct ltstr 85 | { 86 | bool operator()(const MString& s1, const MString& s2) const 87 | { 88 | return strcmp(s1.asChar(), s2.asChar()) < 0; 89 | } 90 | }; 91 | 92 | MStatus OverlappingUVShells::doIt(const MArgList& args) 93 | { 94 | MStatus stat; 95 | 96 | MString meshName = args.asString(0, &stat);err 97 | MSelectionList list; 98 | list.add(meshName); 99 | MDagPath path; 100 | stat = list.getDagPath(0, path);err 101 | MFnMesh fnMesh(path, &stat);err 102 | 103 | MObjectArray objs = UVCommon::getUVShells(fnMesh); 104 | 105 | cout << "number of objects " << objs.length() << endl; 106 | 107 | vector boxes(objs.length()); 108 | 109 | set overlappingUVs; 110 | 111 | MItMeshPolygon originalMeshItp(path, MObject::kNullObj, &stat);err 112 | 113 | for (size_t i = 0; i < objs.length(); i++) 114 | { 115 | MItMeshVertex itmeshv(objs[i], &stat); 116 | while(itmeshv.isDone(&stat) == false) 117 | { 118 | err; 119 | boxes[i].expand(itmeshv.position(MSpace::kObject, &stat));err 120 | itmeshv.next(); 121 | } 122 | } 123 | 124 | MString cmd = "select -add "; 125 | MString tmp = ""; 126 | bool polyOverlapped = false; 127 | 128 | for (size_t i = 0; i < boxes.size(); i++) 129 | { 130 | for (size_t j = i; j < boxes.size(); j++) 131 | { 132 | if (i != j) 133 | { 134 | // cout << "testing " << i << " and " << j << endl; 135 | if (boxes[i].intersects(boxes[j], 0.001)) 136 | { 137 | MItMeshPolygon itmeshpi(objs[i], &stat);err 138 | MItMeshPolygon itmeshpj(objs[j], &stat);err 139 | MFnDagNode dagi(objs[i], &stat);err 140 | MString dagistr = dagi.fullPathName(&stat);err 141 | MFnDagNode dagj(objs[j], &stat);err 142 | MString dagjstr = dagj.fullPathName(&stat);err 143 | while(itmeshpi.isDone(&stat) == false) 144 | { 145 | bool ti = itmeshpi.hasValidTriangulation(&stat);err 146 | if (ti) 147 | { 148 | polyOverlapped = false; 149 | MIntArray vertices; 150 | stat = itmeshpi.getVertices(vertices); 151 | MIntArray UVsi(vertices.length()); 152 | for (size_t k = 0; k < vertices.length(); k++) 153 | { 154 | itmeshpi.getUVIndex(k, UVsi[k]); 155 | tmp += dagistr + ".map[" + UVsi[k] + "] "; 156 | } 157 | 158 | int triCounti; 159 | stat = itmeshpi.numTriangles(triCounti);er 160 | for (int tci = 0; tci < triCounti; tci++) 161 | { 162 | MPointArray trii; 163 | MIntArray vertexListi; 164 | stat = itmeshpi.getTriangle(tci, trii, vertexListi, MSpace::kWorld); 165 | while(itmeshpj.isDone(&stat) == false) 166 | { 167 | bool tj = itmeshpj.hasValidTriangulation(&stat);err 168 | if (tj) 169 | { 170 | int triCountj; 171 | stat = itmeshpj.numTriangles(triCountj);er 172 | for (int tcj = 0; tcj < triCountj; tcj++) 173 | { 174 | MPointArray trij; 175 | MIntArray vertexListj; 176 | stat = itmeshpj.getTriangle(tcj, trij, vertexListj, MSpace::kWorld); 177 | 178 | double p1[2] = {trii[0].x, trii[0].z}; 179 | double q1[2] = {trii[1].x, trii[1].z}; 180 | double r1[2] = {trii[2].x, trii[2].z}; 181 | 182 | cout << "p1 x " << p1[0] << "y " << p1[1] << endl; 183 | 184 | double p2[2] = {trij[0].x, trij[0].z}; 185 | double q2[2] = {trij[1].x, trij[1].z}; 186 | double r2[2] = {trij[2].x, trij[2].z}; 187 | 188 | cout << "p2 x " << p2[0] << "y " << p2[1] << endl; 189 | 190 | if ( tri_tri_overlap_test_2d(p1, q1, r1, p2, q2, r2)) 191 | { 192 | // cout << "TRIANGLES OVERLAP" << endl; 193 | polyOverlapped = true; 194 | goto end; 195 | } 196 | } 197 | } 198 | itmeshpj.next(); 199 | } 200 | } 201 | if (polyOverlapped) 202 | { 203 | cmd += tmp; 204 | } 205 | } 206 | itmeshpi.next(); 207 | } 208 | // cout << i << " intersects " << j << endl; 209 | } 210 | } 211 | } 212 | } 213 | 214 | end: 215 | 216 | for (size_t i = 0; i < objs.length(); i++) 217 | stat = MGlobal::deleteNode( objs[i] );err 218 | 219 | setResult(polyOverlapped); 220 | 221 | return stat; 222 | } 223 | 224 | 225 | // UNDO THE COMMAND 226 | MStatus OverlappingUVShells::undoIt() 227 | { 228 | return MStatus(); 229 | } 230 | -------------------------------------------------------------------------------- /src/overlappingUVShells.h: -------------------------------------------------------------------------------- 1 | #ifndef _OVERLAPPING_UV_SHELLS_H_ 2 | #define _OVERLAPPING_UV_SHELLS_H_ 3 | 4 | #include 5 | #include 6 | 7 | //! This class represents the plugin to check whether UVs are overlapping 8 | class OverlappingUVShells : public MPxCommand 9 | { 10 | public: 11 | //! Default public constructor 12 | OverlappingUVShells(); 13 | 14 | //! Default public destructor 15 | virtual ~OverlappingUVShells(); 16 | 17 | //! Node creator 18 | static void* creator(); 19 | 20 | //! Specifies whether the action is undable 21 | bool isUndoable() const; 22 | 23 | //! Performs the node's duty 24 | MStatus doIt(const MArgList&); 25 | 26 | //! Undoes what was done in doIt 27 | MStatus undoIt(); 28 | 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/pluginMain.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "intersect.h" 4 | #include "UVSeams.h" 5 | #include "overlappingUVShells.h" 6 | #include "UVReversed.h" 7 | #include "Renaming.h" 8 | #include "holesBorder.h" 9 | 10 | #define er if (stat != MS::kSuccess) cout << "trolol " << __FILE__ << ":" << __LINE__ << endl; 11 | 12 | MStatus initializePlugin( MObject obj ) 13 | { 14 | MFnPlugin plugin( obj, "Oliver Shyal Beardsley", "V1.0.0", "osb" ); 15 | 16 | MStatus stat; 17 | stat = plugin.registerCommand("checkNormalDirection", checkNormalDirection::creator);er 18 | stat = plugin.registerCommand("UVSeams", UVSeams::creator);er 19 | stat = plugin.registerCommand("OverlappingUVShells", OverlappingUVShells::creator);er 20 | stat = plugin.registerCommand("UVReversed", UVReversed::creator);er 21 | stat = plugin.registerCommand("osbTypeRename", TypeRename::creator);er 22 | stat = plugin.registerCommand("holesBorder", holesBorder::creator);er 23 | return MS::kSuccess; 24 | } 25 | 26 | MStatus uninitializePlugin( MObject obj) 27 | { 28 | MFnPlugin plugin( obj ); 29 | 30 | MStatus stat; 31 | 32 | stat = plugin.deregisterCommand("holesBorder");er 33 | stat = plugin.deregisterCommand("osbTypeRename");er 34 | stat = plugin.deregisterCommand("UVReversed");er 35 | stat = plugin.deregisterCommand("OverlappingUVShells");er 36 | stat = plugin.deregisterCommand("UVSeams");er 37 | stat = plugin.deregisterCommand("checkNormalDirection");er 38 | return MS::kSuccess; 39 | } 40 | -------------------------------------------------------------------------------- /src/triangleOverlappingTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Triangle-Triangle Overlap Test Routines 4 | * July, 2002 5 | * Updated December 2003 6 | * 7 | * This file contains C implementation of algorithms for 8 | * performing two and three-dimensional triangle-triangle intersection test 9 | * The algorithms and underlying theory are described in 10 | * 11 | * "Fast and Robust Triangle-Triangle Overlap Test 12 | * Using Orientation Predicates" P. Guigue - O. Devillers 13 | * 14 | * Journal of Graphics Tools, 8(1), 2003 15 | * 16 | * Several geometric predicates are defined. Their parameters are all 17 | * points. Each point is an array of two or three double precision 18 | * floating point numbers. The geometric predicates implemented in 19 | * this file are: 20 | * 21 | * int tri_tri_overlap_test_3d(p1,q1,r1,p2,q2,r2) 22 | * int tri_tri_overlap_test_2d(p1,q1,r1,p2,q2,r2) 23 | * 24 | * int tri_tri_intersection_test_3d(p1,q1,r1,p2,q2,r2, 25 | * coplanar,source,target) 26 | * 27 | * is a version that computes the segment of intersection when 28 | * the triangles overlap (and are not coplanar) 29 | * 30 | * each function returns 1 if the triangles (including their 31 | * boundary) intersect, otherwise 0 32 | * 33 | * 34 | * Other information are available from the Web page 35 | * http://www.acm.org/jgt/papers/GuigueDevillers03/ 36 | * 37 | */ 38 | 39 | 40 | 41 | /* function prototype */ 42 | 43 | int tri_tri_overlap_test_3d(double p1[3], double q1[3], double r1[3], 44 | double p2[3], double q2[3], double r2[3]); 45 | 46 | 47 | int coplanar_tri_tri3d(double p1[3], double q1[3], double r1[3], 48 | double p2[3], double q2[3], double r2[3], 49 | double N1[3], double N2[3]); 50 | 51 | 52 | int tri_tri_overlap_test_2d(double p1[2], double q1[2], double r1[2], 53 | double p2[2], double q2[2], double r2[2]); 54 | 55 | 56 | int tri_tri_intersection_test_3d(double p1[3], double q1[3], double r1[3], 57 | double p2[3], double q2[3], double r2[3], 58 | int * coplanar, 59 | double source[3],double target[3]); 60 | 61 | /* coplanar returns whether the triangles are coplanar 62 | * source and target are the endpoints of the segment of 63 | * intersection if it exists) 64 | */ 65 | 66 | 67 | /* some 3D macros */ 68 | 69 | #define CROSS(dest,v1,v2) \ 70 | dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ 71 | dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ 72 | dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; 73 | 74 | #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) 75 | 76 | 77 | 78 | #define SUB(dest,v1,v2) dest[0]=v1[0]-v2[0]; \ 79 | dest[1]=v1[1]-v2[1]; \ 80 | dest[2]=v1[2]-v2[2]; 81 | 82 | 83 | #define SCALAR(dest,alpha,v) dest[0] = alpha * v[0]; \ 84 | dest[1] = alpha * v[1]; \ 85 | dest[2] = alpha * v[2]; 86 | 87 | 88 | 89 | #define CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2) {\ 90 | SUB(v1,p2,q1)\ 91 | SUB(v2,p1,q1)\ 92 | CROSS(N1,v1,v2)\ 93 | SUB(v1,q2,q1)\ 94 | if (DOT(v1,N1) > 0.0f) return 0;\ 95 | SUB(v1,p2,p1)\ 96 | SUB(v2,r1,p1)\ 97 | CROSS(N1,v1,v2)\ 98 | SUB(v1,r2,p1) \ 99 | if (DOT(v1,N1) > 0.0f) return 0;\ 100 | else return 1; } 101 | 102 | 103 | 104 | /* Permutation in a canonical form of T2's vertices */ 105 | 106 | #define TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) { \ 107 | if (dp2 > 0.0f) { \ 108 | if (dq2 > 0.0f) CHECK_MIN_MAX(p1,r1,q1,r2,p2,q2) \ 109 | else if (dr2 > 0.0f) CHECK_MIN_MAX(p1,r1,q1,q2,r2,p2)\ 110 | else CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2) }\ 111 | else if (dp2 < 0.0f) { \ 112 | if (dq2 < 0.0f) CHECK_MIN_MAX(p1,q1,r1,r2,p2,q2)\ 113 | else if (dr2 < 0.0f) CHECK_MIN_MAX(p1,q1,r1,q2,r2,p2)\ 114 | else CHECK_MIN_MAX(p1,r1,q1,p2,q2,r2)\ 115 | } else { \ 116 | if (dq2 < 0.0f) { \ 117 | if (dr2 >= 0.0f) CHECK_MIN_MAX(p1,r1,q1,q2,r2,p2)\ 118 | else CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2)\ 119 | } \ 120 | else if (dq2 > 0.0f) { \ 121 | if (dr2 > 0.0f) CHECK_MIN_MAX(p1,r1,q1,p2,q2,r2)\ 122 | else CHECK_MIN_MAX(p1,q1,r1,q2,r2,p2)\ 123 | } \ 124 | else { \ 125 | if (dr2 > 0.0f) CHECK_MIN_MAX(p1,q1,r1,r2,p2,q2)\ 126 | else if (dr2 < 0.0f) CHECK_MIN_MAX(p1,r1,q1,r2,p2,q2)\ 127 | else return coplanar_tri_tri3d(p1,q1,r1,p2,q2,r2,N1,N2);\ 128 | }}} 129 | 130 | 131 | 132 | /* 133 | * 134 | * Three-dimensional Triangle-Triangle Overlap Test 135 | * 136 | */ 137 | 138 | 139 | int tri_tri_overlap_test_3d(double p1[3], double q1[3], double r1[3], 140 | 141 | double p2[3], double q2[3], double r2[3]) 142 | { 143 | double dp1, dq1, dr1, dp2, dq2, dr2; 144 | double v1[3], v2[3]; 145 | double N1[3], N2[3]; 146 | 147 | /* Compute distance signs of p1, q1 and r1 to the plane of 148 | triangle(p2,q2,r2) */ 149 | 150 | 151 | SUB(v1,p2,r2) 152 | SUB(v2,q2,r2) 153 | CROSS(N2,v1,v2) 154 | 155 | SUB(v1,p1,r2) 156 | dp1 = DOT(v1,N2); 157 | SUB(v1,q1,r2) 158 | dq1 = DOT(v1,N2); 159 | SUB(v1,r1,r2) 160 | dr1 = DOT(v1,N2); 161 | 162 | if (((dp1 * dq1) > 0.0f) && ((dp1 * dr1) > 0.0f)) return 0; 163 | 164 | /* Compute distance signs of p2, q2 and r2 to the plane of 165 | triangle(p1,q1,r1) */ 166 | 167 | 168 | SUB(v1,q1,p1) 169 | SUB(v2,r1,p1) 170 | CROSS(N1,v1,v2) 171 | 172 | SUB(v1,p2,r1) 173 | dp2 = DOT(v1,N1); 174 | SUB(v1,q2,r1) 175 | dq2 = DOT(v1,N1); 176 | SUB(v1,r2,r1) 177 | dr2 = DOT(v1,N1); 178 | 179 | if (((dp2 * dq2) > 0.0f) && ((dp2 * dr2) > 0.0f)) return 0; 180 | 181 | /* Permutation in a canonical form of T1's vertices */ 182 | 183 | 184 | if (dp1 > 0.0f) { 185 | if (dq1 > 0.0f) TRI_TRI_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) 186 | else if (dr1 > 0.0f) TRI_TRI_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) 187 | else TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) 188 | } else if (dp1 < 0.0f) { 189 | if (dq1 < 0.0f) TRI_TRI_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) 190 | else if (dr1 < 0.0f) TRI_TRI_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) 191 | else TRI_TRI_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) 192 | } else { 193 | if (dq1 < 0.0f) { 194 | if (dr1 >= 0.0f) TRI_TRI_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) 195 | else TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) 196 | } 197 | else if (dq1 > 0.0f) { 198 | if (dr1 > 0.0f) TRI_TRI_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) 199 | else TRI_TRI_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) 200 | } 201 | else { 202 | if (dr1 > 0.0f) TRI_TRI_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) 203 | else if (dr1 < 0.0f) TRI_TRI_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) 204 | else return coplanar_tri_tri3d(p1,q1,r1,p2,q2,r2,N1,N2); 205 | } 206 | } 207 | }; 208 | 209 | 210 | 211 | int coplanar_tri_tri3d(double p1[3], double q1[3], double r1[3], 212 | double p2[3], double q2[3], double r2[3], 213 | double normal_1[3], double [3]){ 214 | 215 | double P1[2],Q1[2],R1[2]; 216 | double P2[2],Q2[2],R2[2]; 217 | 218 | double n_x, n_y, n_z; 219 | 220 | n_x = ((normal_1[0]<0)?-normal_1[0]:normal_1[0]); 221 | n_y = ((normal_1[1]<0)?-normal_1[1]:normal_1[1]); 222 | n_z = ((normal_1[2]<0)?-normal_1[2]:normal_1[2]); 223 | 224 | 225 | /* Projection of the triangles in 3D onto 2D such that the area of 226 | the projection is maximized. */ 227 | 228 | 229 | if (( n_x > n_z ) && ( n_x >= n_y )) { 230 | // Project onto plane YZ 231 | 232 | P1[0] = q1[2]; P1[1] = q1[1]; 233 | Q1[0] = p1[2]; Q1[1] = p1[1]; 234 | R1[0] = r1[2]; R1[1] = r1[1]; 235 | 236 | P2[0] = q2[2]; P2[1] = q2[1]; 237 | Q2[0] = p2[2]; Q2[1] = p2[1]; 238 | R2[0] = r2[2]; R2[1] = r2[1]; 239 | 240 | } else if (( n_y > n_z ) && ( n_y >= n_x )) { 241 | // Project onto plane XZ 242 | 243 | P1[0] = q1[0]; P1[1] = q1[2]; 244 | Q1[0] = p1[0]; Q1[1] = p1[2]; 245 | R1[0] = r1[0]; R1[1] = r1[2]; 246 | 247 | P2[0] = q2[0]; P2[1] = q2[2]; 248 | Q2[0] = p2[0]; Q2[1] = p2[2]; 249 | R2[0] = r2[0]; R2[1] = r2[2]; 250 | 251 | } else { 252 | // Project onto plane XY 253 | 254 | P1[0] = p1[0]; P1[1] = p1[1]; 255 | Q1[0] = q1[0]; Q1[1] = q1[1]; 256 | R1[0] = r1[0]; R1[1] = r1[1]; 257 | 258 | P2[0] = p2[0]; P2[1] = p2[1]; 259 | Q2[0] = q2[0]; Q2[1] = q2[1]; 260 | R2[0] = r2[0]; R2[1] = r2[1]; 261 | } 262 | 263 | return tri_tri_overlap_test_2d(P1,Q1,R1,P2,Q2,R2); 264 | 265 | }; 266 | 267 | 268 | 269 | /* 270 | * 271 | * Three-dimensional Triangle-Triangle Intersection 272 | * 273 | */ 274 | 275 | /* 276 | This macro is called when the triangles surely intersect 277 | It constructs the segment of intersection of the two triangles 278 | if they are not coplanar. 279 | */ 280 | 281 | #define CONSTRUCT_INTERSECTION(p1,q1,r1,p2,q2,r2) { \ 282 | SUB(v1,q1,p1) \ 283 | SUB(v2,r2,p1) \ 284 | CROSS(N,v1,v2) \ 285 | SUB(v,p2,p1) \ 286 | if (DOT(v,N) > 0.0f) {\ 287 | SUB(v1,r1,p1) \ 288 | CROSS(N,v1,v2) \ 289 | if (DOT(v,N) <= 0.0f) { \ 290 | SUB(v2,q2,p1) \ 291 | CROSS(N,v1,v2) \ 292 | if (DOT(v,N) > 0.0f) { \ 293 | SUB(v1,p1,p2) \ 294 | SUB(v2,p1,r1) \ 295 | alpha = DOT(v1,N2) / DOT(v2,N2); \ 296 | SCALAR(v1,alpha,v2) \ 297 | SUB(source,p1,v1) \ 298 | SUB(v1,p2,p1) \ 299 | SUB(v2,p2,r2) \ 300 | alpha = DOT(v1,N1) / DOT(v2,N1); \ 301 | SCALAR(v1,alpha,v2) \ 302 | SUB(target,p2,v1) \ 303 | return 1; \ 304 | } else { \ 305 | SUB(v1,p2,p1) \ 306 | SUB(v2,p2,q2) \ 307 | alpha = DOT(v1,N1) / DOT(v2,N1); \ 308 | SCALAR(v1,alpha,v2) \ 309 | SUB(source,p2,v1) \ 310 | SUB(v1,p2,p1) \ 311 | SUB(v2,p2,r2) \ 312 | alpha = DOT(v1,N1) / DOT(v2,N1); \ 313 | SCALAR(v1,alpha,v2) \ 314 | SUB(target,p2,v1) \ 315 | return 1; \ 316 | } \ 317 | } else { \ 318 | return 0; \ 319 | } \ 320 | } else { \ 321 | SUB(v2,q2,p1) \ 322 | CROSS(N,v1,v2) \ 323 | if (DOT(v,N) < 0.0f) { \ 324 | return 0; \ 325 | } else { \ 326 | SUB(v1,r1,p1) \ 327 | CROSS(N,v1,v2) \ 328 | if (DOT(v,N) >= 0.0f) { \ 329 | SUB(v1,p1,p2) \ 330 | SUB(v2,p1,r1) \ 331 | alpha = DOT(v1,N2) / DOT(v2,N2); \ 332 | SCALAR(v1,alpha,v2) \ 333 | SUB(source,p1,v1) \ 334 | SUB(v1,p1,p2) \ 335 | SUB(v2,p1,q1) \ 336 | alpha = DOT(v1,N2) / DOT(v2,N2); \ 337 | SCALAR(v1,alpha,v2) \ 338 | SUB(target,p1,v1) \ 339 | return 1; \ 340 | } else { \ 341 | SUB(v1,p2,p1) \ 342 | SUB(v2,p2,q2) \ 343 | alpha = DOT(v1,N1) / DOT(v2,N1); \ 344 | SCALAR(v1,alpha,v2) \ 345 | SUB(source,p2,v1) \ 346 | SUB(v1,p1,p2) \ 347 | SUB(v2,p1,q1) \ 348 | alpha = DOT(v1,N2) / DOT(v2,N2); \ 349 | SCALAR(v1,alpha,v2) \ 350 | SUB(target,p1,v1) \ 351 | return 1; \ 352 | }}}} 353 | 354 | 355 | 356 | #define TRI_TRI_INTER_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) { \ 357 | if (dp2 > 0.0f) { \ 358 | if (dq2 > 0.0f) CONSTRUCT_INTERSECTION(p1,r1,q1,r2,p2,q2) \ 359 | else if (dr2 > 0.0f) CONSTRUCT_INTERSECTION(p1,r1,q1,q2,r2,p2)\ 360 | else CONSTRUCT_INTERSECTION(p1,q1,r1,p2,q2,r2) }\ 361 | else if (dp2 < 0.0f) { \ 362 | if (dq2 < 0.0f) CONSTRUCT_INTERSECTION(p1,q1,r1,r2,p2,q2)\ 363 | else if (dr2 < 0.0f) CONSTRUCT_INTERSECTION(p1,q1,r1,q2,r2,p2)\ 364 | else CONSTRUCT_INTERSECTION(p1,r1,q1,p2,q2,r2)\ 365 | } else { \ 366 | if (dq2 < 0.0f) { \ 367 | if (dr2 >= 0.0f) CONSTRUCT_INTERSECTION(p1,r1,q1,q2,r2,p2)\ 368 | else CONSTRUCT_INTERSECTION(p1,q1,r1,p2,q2,r2)\ 369 | } \ 370 | else if (dq2 > 0.0f) { \ 371 | if (dr2 > 0.0f) CONSTRUCT_INTERSECTION(p1,r1,q1,p2,q2,r2)\ 372 | else CONSTRUCT_INTERSECTION(p1,q1,r1,q2,r2,p2)\ 373 | } \ 374 | else { \ 375 | if (dr2 > 0.0f) CONSTRUCT_INTERSECTION(p1,q1,r1,r2,p2,q2)\ 376 | else if (dr2 < 0.0f) CONSTRUCT_INTERSECTION(p1,r1,q1,r2,p2,q2)\ 377 | else { \ 378 | *coplanar = 1; \ 379 | return coplanar_tri_tri3d(p1,q1,r1,p2,q2,r2,N1,N2);\ 380 | } \ 381 | }} } 382 | 383 | 384 | /* 385 | The following version computes the segment of intersection of the 386 | two triangles if it exists. 387 | coplanar returns whether the triangles are coplanar 388 | source and target are the endpoints of the line segment of intersection 389 | */ 390 | 391 | int tri_tri_intersection_test_3d(double p1[3], double q1[3], double r1[3], 392 | double p2[3], double q2[3], double r2[3], 393 | int * coplanar, 394 | double source[3], double target[3] ) 395 | 396 | { 397 | double dp1, dq1, dr1, dp2, dq2, dr2; 398 | double v1[3], v2[3], v[3]; 399 | double N1[3], N2[3], N[3]; 400 | double alpha; 401 | 402 | // Compute distance signs of p1, q1 and r1 403 | // to the plane of triangle(p2,q2,r2) 404 | 405 | 406 | SUB(v1,p2,r2) 407 | SUB(v2,q2,r2) 408 | CROSS(N2,v1,v2) 409 | 410 | SUB(v1,p1,r2) 411 | dp1 = DOT(v1,N2); 412 | SUB(v1,q1,r2) 413 | dq1 = DOT(v1,N2); 414 | SUB(v1,r1,r2) 415 | dr1 = DOT(v1,N2); 416 | 417 | if (((dp1 * dq1) > 0.0f) && ((dp1 * dr1) > 0.0f)) return 0; 418 | 419 | // Compute distance signs of p2, q2 and r2 420 | // to the plane of triangle(p1,q1,r1) 421 | 422 | 423 | SUB(v1,q1,p1) 424 | SUB(v2,r1,p1) 425 | CROSS(N1,v1,v2) 426 | 427 | SUB(v1,p2,r1) 428 | dp2 = DOT(v1,N1); 429 | SUB(v1,q2,r1) 430 | dq2 = DOT(v1,N1); 431 | SUB(v1,r2,r1) 432 | dr2 = DOT(v1,N1); 433 | 434 | if (((dp2 * dq2) > 0.0f) && ((dp2 * dr2) > 0.0f)) return 0; 435 | 436 | // Permutation in a canonical form of T1's vertices 437 | 438 | 439 | if (dp1 > 0.0f) { 440 | if (dq1 > 0.0f) TRI_TRI_INTER_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) 441 | else if (dr1 > 0.0f) TRI_TRI_INTER_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) 442 | 443 | else TRI_TRI_INTER_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) 444 | } else if (dp1 < 0.0f) { 445 | if (dq1 < 0.0f) TRI_TRI_INTER_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) 446 | else if (dr1 < 0.0f) TRI_TRI_INTER_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) 447 | else TRI_TRI_INTER_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) 448 | } else { 449 | if (dq1 < 0.0f) { 450 | if (dr1 >= 0.0f) TRI_TRI_INTER_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) 451 | else TRI_TRI_INTER_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) 452 | } 453 | else if (dq1 > 0.0f) { 454 | if (dr1 > 0.0f) TRI_TRI_INTER_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) 455 | else TRI_TRI_INTER_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) 456 | } 457 | else { 458 | if (dr1 > 0.0f) TRI_TRI_INTER_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) 459 | else if (dr1 < 0.0f) TRI_TRI_INTER_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) 460 | else { 461 | // triangles are co-planar 462 | 463 | *coplanar = 1; 464 | return coplanar_tri_tri3d(p1,q1,r1,p2,q2,r2,N1,N2); 465 | } 466 | } 467 | } 468 | }; 469 | 470 | 471 | 472 | 473 | 474 | /* 475 | * 476 | * Two dimensional Triangle-Triangle Overlap Test 477 | * 478 | */ 479 | 480 | 481 | /* some 2D macros */ 482 | 483 | #define ORIENT_2D(a, b, c) ((a[0]-c[0])*(b[1]-c[1])-(a[1]-c[1])*(b[0]-c[0])) 484 | 485 | 486 | #define INTERSECTION_TEST_VERTEX(P1, Q1, R1, P2, Q2, R2) {\ 487 | if (ORIENT_2D(R2,P2,Q1) >= 0.0f)\ 488 | if (ORIENT_2D(R2,Q2,Q1) <= 0.0f)\ 489 | if (ORIENT_2D(P1,P2,Q1) > 0.0f) {\ 490 | if (ORIENT_2D(P1,Q2,Q1) <= 0.0f) return 1; \ 491 | else return 0;} else {\ 492 | if (ORIENT_2D(P1,P2,R1) >= 0.0f)\ 493 | if (ORIENT_2D(Q1,R1,P2) >= 0.0f) return 1; \ 494 | else return 0;\ 495 | else return 0;}\ 496 | else \ 497 | if (ORIENT_2D(P1,Q2,Q1) <= 0.0f)\ 498 | if (ORIENT_2D(R2,Q2,R1) <= 0.0f)\ 499 | if (ORIENT_2D(Q1,R1,Q2) >= 0.0f) return 1; \ 500 | else return 0;\ 501 | else return 0;\ 502 | else return 0;\ 503 | else\ 504 | if (ORIENT_2D(R2,P2,R1) >= 0.0f) \ 505 | if (ORIENT_2D(Q1,R1,R2) >= 0.0f)\ 506 | if (ORIENT_2D(P1,P2,R1) >= 0.0f) return 1;\ 507 | else return 0;\ 508 | else \ 509 | if (ORIENT_2D(Q1,R1,Q2) >= 0.0f) {\ 510 | if (ORIENT_2D(R2,R1,Q2) >= 0.0f) return 1; \ 511 | else return 0; }\ 512 | else return 0; \ 513 | else return 0; \ 514 | }; 515 | 516 | 517 | 518 | #define INTERSECTION_TEST_EDGE(P1, Q1, R1, P2, Q2, R2) { \ 519 | if (ORIENT_2D(R2,P2,Q1) >= 0.0f) {\ 520 | if (ORIENT_2D(P1,P2,Q1) >= 0.0f) { \ 521 | if (ORIENT_2D(P1,Q1,R2) >= 0.0f) return 1; \ 522 | else return 0;} else { \ 523 | if (ORIENT_2D(Q1,R1,P2) >= 0.0f){ \ 524 | if (ORIENT_2D(R1,P1,P2) >= 0.0f) return 1; else return 0;} \ 525 | else return 0; } \ 526 | } else {\ 527 | if (ORIENT_2D(R2,P2,R1) >= 0.0f) {\ 528 | if (ORIENT_2D(P1,P2,R1) >= 0.0f) {\ 529 | if (ORIENT_2D(P1,R1,R2) >= 0.0f) return 1; \ 530 | else {\ 531 | if (ORIENT_2D(Q1,R1,R2) >= 0.0f) return 1; else return 0;}}\ 532 | else return 0; }\ 533 | else return 0; }} 534 | 535 | 536 | 537 | int ccw_tri_tri_intersection_2d(double p1[2], double q1[2], double r1[2], 538 | double p2[2], double q2[2], double r2[2]) { 539 | if ( ORIENT_2D(p2,q2,p1) >= 0.0f ) { 540 | if ( ORIENT_2D(q2,r2,p1) >= 0.0f ) { 541 | if ( ORIENT_2D(r2,p2,p1) >= 0.0f ) return 1; 542 | else INTERSECTION_TEST_EDGE(p1,q1,r1,p2,q2,r2) 543 | } else { 544 | if ( ORIENT_2D(r2,p2,p1) >= 0.0f ) 545 | INTERSECTION_TEST_EDGE(p1,q1,r1,r2,p2,q2) 546 | else INTERSECTION_TEST_VERTEX(p1,q1,r1,p2,q2,r2)}} 547 | else { 548 | if ( ORIENT_2D(q2,r2,p1) >= 0.0f ) { 549 | if ( ORIENT_2D(r2,p2,p1) >= 0.0f ) 550 | INTERSECTION_TEST_EDGE(p1,q1,r1,q2,r2,p2) 551 | else INTERSECTION_TEST_VERTEX(p1,q1,r1,q2,r2,p2)} 552 | else INTERSECTION_TEST_VERTEX(p1,q1,r1,r2,p2,q2)} 553 | }; 554 | 555 | 556 | int tri_tri_overlap_test_2d(double p1[2], double q1[2], double r1[2], 557 | double p2[2], double q2[2], double r2[2]) { 558 | if ( ORIENT_2D(p1,q1,r1) < 0.0f ) 559 | if ( ORIENT_2D(p2,q2,r2) < 0.0f ) 560 | return ccw_tri_tri_intersection_2d(p1,r1,q1,p2,r2,q2); 561 | else 562 | return ccw_tri_tri_intersection_2d(p1,r1,q1,p2,q2,r2); 563 | else 564 | if ( ORIENT_2D(p2,q2,r2) < 0.0f ) 565 | return ccw_tri_tri_intersection_2d(p1,q1,r1,p2,r2,q2); 566 | else 567 | return ccw_tri_tri_intersection_2d(p1,q1,r1,p2,q2,r2); 568 | 569 | }; 570 | 571 | -------------------------------------------------------------------------------- /ui/osbSanityCheckHelp.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | from PyQt4.QtCore import * 3 | from PyQt4.QtGui import * 4 | import maya.cmds as cmds 5 | import maya.mel as mel 6 | 7 | from pfUtils.v1_2.qt.dialog import PfQDialog 8 | 9 | import osbTools.v1_0 10 | reload(osbTools) 11 | from osbTools.v1_0 import osbSanityCheckHelp_UI 12 | 13 | global w 14 | 15 | class win(PfQDialog): 16 | def __init__(self, parent=None, modal=False): 17 | #call parent's init 18 | PfQDialog.__init__(self, parent, modal=modal) 19 | 20 | #setup main UI from QtDesigner file 21 | self.ui = osbSanityCheckHelp_UI.Ui_Dialog() 22 | self.ui.setupUi( self ) 23 | self.setObjectName('osbSanityCheck') 24 | self.ui.textEdit.insertHtml("\ 25 | \ 26 | \ 27 | \ 28 | \ 29 | The sanity checker is a simple API allowing you to easily add your
\ 30 | own checks.
\ 31 |
\ 32 | It is currently installed in:
\ 33 |
\ 34 |
\ 35 |
\ 36 | In that same folder you will find a file called \"userChecks.mel\" you can either put your own checks in userChecks.mel directly, or put them in seperate mel files and source those files from userChecks.mel
\ 37 |
\ 38 | Your checks should start with:
\ 39 |
\ 40 | source \"osbSanityCheckerAPI.mel\";
\ 41 |
\ 42 | The registration command is:
\ 43 |
\ 44 | osbAddSanityCheck(\"exampleCheckName\",
\ 45 | \"Example Category Name\",
\ 46 | \"Example label - this name appears in the UI\",
\ 47 | \"Example Tooltip - this help shows up when hovering over the check in the UI\",
\ 48 | \"Perform\");
\ 49 |
\ 50 | The last string can either be \"Perform\" or \"Perform,Select,fix\". A \"Perform\" check will do all that is required in one function. For this check you'll need to declare and define a global function that has the same name as the first argument, so:
\ 51 |
\ 52 | global proc exampleCheckName()
\ 53 | {
\ 54 | // checking code here
\ 55 | }
\ 56 |
\ 57 | The function signature contains no arguments and the function has no return value. Within the function, you can assume that the correct objects that you want to check are currently selected.
\ 58 |
\ 59 | The second kind of check is \"Perform,Select,fix\". For this type of check, the objects / components which remain selected when exampleCheckName() returns are the objects that will get added to the selection set which flags them as being problematic.
\ 60 |
\ 61 | global proc exampleCheckNameFix()
\ 62 | {
\ 63 | // fixing code here
\ 64 | }
\ 65 |
\ 66 | Once again, in this function, you can assume that the problematic objects / components that you want to fix are currently selected.
\ 67 |
\ 68 | Your best option to get up to running is to take a look at existing checks inside the 'checks' directory.
\ 69 |
\ 70 | If the checks that you add are used a lot please feel free to add them to the main tool and check your changes into the newton repos in bitbucket.
\ 71 | Please also note that existing checks can be hidding by using edit > Hide selected checks, go ahead and hide checks that you do not use, and implement your own checks to make this tool your own.\ 72 | \ 73 | \ 74 | \ 75 | ") 76 | 77 | def main(): 78 | global w 79 | w = win() 80 | w.show() 81 | -------------------------------------------------------------------------------- /ui/osbSanityCheckHelp_UI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'osbSanityCheckHelp_UI.ui' 4 | # 5 | # Created: Wed May 9 20:06:30 2012 6 | # by: PyQt4 UI code generator 4.7.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | class Ui_Dialog(object): 13 | def setupUi(self, Dialog): 14 | Dialog.setObjectName("Dialog") 15 | Dialog.resize(400, 300) 16 | self.horizontalLayout = QtGui.QHBoxLayout(Dialog) 17 | self.horizontalLayout.setObjectName("horizontalLayout") 18 | self.textEdit = QtGui.QTextEdit(Dialog) 19 | self.textEdit.setObjectName("textEdit") 20 | self.horizontalLayout.addWidget(self.textEdit) 21 | 22 | self.retranslateUi(Dialog) 23 | QtCore.QMetaObject.connectSlotsByName(Dialog) 24 | 25 | def retranslateUi(self, Dialog): 26 | Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8)) 27 | 28 | -------------------------------------------------------------------------------- /ui/osbSanityCheckHelp_UI.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 827 10 | 838 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /windows/newton.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 11.00 2 | # Visual Studio 2010 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "newton", "newton.vcxproj", "{681412B0-F197-4A2F-9263-DEA2E8690146}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|x64 = Debug|x64 8 | Release|x64 = Release|x64 9 | ReleaseDebug|x64 = ReleaseDebug|x64 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Debug|x64.ActiveCfg = Debug|x64 13 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Debug|x64.Build.0 = Debug|x64 14 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Release|x64.ActiveCfg = Release|x64 15 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Release|x64.Build.0 = Release|x64 16 | {681412B0-F197-4A2F-9263-DEA2E8690146}.ReleaseDebug|x64.ActiveCfg = ReleaseDebug|x64 17 | {681412B0-F197-4A2F-9263-DEA2E8690146}.ReleaseDebug|x64.Build.0 = ReleaseDebug|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /windows/newton.sln.old: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 10.00 2 | # Visual Studio 2008 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "newton", "newton.vcproj", "{681412B0-F197-4A2F-9263-DEA2E8690146}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|x64 = Debug|x64 8 | Release|x64 = Release|x64 9 | ReleaseDebug|x64 = ReleaseDebug|x64 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Debug|x64.ActiveCfg = Debug|x64 13 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Debug|x64.Build.0 = Debug|x64 14 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Release|x64.ActiveCfg = Release|x64 15 | {681412B0-F197-4A2F-9263-DEA2E8690146}.Release|x64.Build.0 = Release|x64 16 | {681412B0-F197-4A2F-9263-DEA2E8690146}.ReleaseDebug|x64.ActiveCfg = ReleaseDebug|x64 17 | {681412B0-F197-4A2F-9263-DEA2E8690146}.ReleaseDebug|x64.Build.0 = ReleaseDebug|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /windows/newton.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 30 | 33 | 36 | 39 | 42 | 51 | 69 | 72 | 77 | 80 | 96 | 99 | 102 | 105 | 108 | 111 | 114 | 117 | 118 | 127 | 130 | 133 | 136 | 139 | 148 | 163 | 166 | 171 | 174 | 190 | 193 | 196 | 199 | 202 | 205 | 208 | 211 | 212 | 221 | 224 | 227 | 230 | 233 | 242 | 259 | 262 | 267 | 270 | 285 | 288 | 291 | 294 | 297 | 300 | 303 | 306 | 307 | 308 | 309 | 310 | 311 | 313 | 315 | 318 | 324 | 325 | 328 | 334 | 335 | 338 | 344 | 345 | 346 | 347 | 349 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | --------------------------------------------------------------------------------