diff --git a/README.md b/README.md index 2362d27..73a15c6 100644 --- a/README.md +++ b/README.md @@ -28,18 +28,39 @@ As long as your package supports Plugins, Python, and Qt (or PySide), you can us * In the future, I *do* have ideas for building an interface to an advanced deformer for dynamically previewing arbitrary splits, but the final output will always have the ability to bake down to a basic blendshape. ### Basic Usage -Follow this youtube link to a basic walkthrough of Simplex usage. This video highlights an older version of Simplex, but the interaction remains basically the same. [https://www.youtube.com/watch?v=LQwzsxU8z_Q](https://www.youtube.com/watch?v=LQwzsxU8z_Q) +Follow this youtube link to a basic walkthrough of Simplex usage. This video highlights a slightly older version of Simplex, but the interaction remains basically the same. [https://www.youtube.com/watch?v=LQwzsxU8z_Q](https://www.youtube.com/watch?v=LQwzsxU8z_Q) -## INSTALLATION -1. Download the latest release -2. Copy the `modules` folder from the zip file into your maya directory. On windows, that would mean copying into `%USERPROFILE%\Documents\maya` so that the module file sits at `%USERPROFILE%\Documents\maya\modules\simplex.mod` -3. Install numpy for mayapy [using pip](https://knowledge.autodesk.com/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2022/ENU/Maya-Scripting/files/GUID-72A245EC-CDB4-46AB-BEE0-4BBBF9791627-htm.html). If you're using a Maya with Python 3, you should just be able to install numpy. For Python 2 on Windows, you'll have to find a .whl file compiled for your version. I'm not sure about Mac or Linux for Py2. -4. Run these two Python commands in Maya to start the tool. (This is probably what you should put into a shelf button) +## Easy Installation +1. Download [this file](https://raw.githubusercontent.com/blurstudio/Simplex/master/simplex_maya_installer.py) to your computer. Make sure it's saved as a python file. +2. Drag/drop the python file into a freshly opened instance of Maya (make sure all other mayas are closed). A command prompt window may open for a couple seconds. This is normal. +3. If you have multiple Maya versions installed, repeat step 2 for those versions as well. This just ensures that numpy is installed for those versions. +4. Create a python shelf button with this script. ```python from simplexui import runSimplexUI runSimplexUI() ``` +## Updating +1. Download [this file](https://raw.githubusercontent.com/blurstudio/Simplex/master/simplex_maya_installer.py) to your computer. Make sure it's saved as a python file. +2. Drag/drop the python file into a freshly opened instance of Maya (make sure all other mayas are closed). A command prompt window may open for a couple seconds. This is normal. +3. If you have multiple Maya versions installed, you do NOT have to repeat step 2 for all of them. + + +## Manual Installation +1. Download the `simplex-v*.*.*.zip` file from the [latest release](https://github.com/blurstudio/Simplex/releases/latest) +2. Create a `modules` folder in your maya user directory. For example, on Windows, that would mean creating `C:\Users\\Documents\maya\modules` +3. Copy the `simplex.mod` file and the `simplex` folder into that directory. +4. Install numpy for mayapy [using pip](https://knowledge.autodesk.com/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2022/ENU/Maya-Scripting/files/GUID-72A245EC-CDB4-46AB-BEE0-4BBBF9791627-htm.html). For example, on Windows, once you're in the right place the command will be `mayapy -m pip install numpy`. You will need admin privelages for this. +5. Run these two Python commands in Maya to start the tool. (This is probably what you should put into a shelf button) +```python +from simplexui import runSimplexUI +runSimplexUI() +``` + +## Uninstalling +1. Delete the `simplex.mod` file and the `simplex` folder from the `modules` folder in your maya user directory. For example, on Windows, that would mean deleting `C:\Users\\Documents\maya\modules\simplex.mod` and `C:\Users\\Documents\maya\modules\simplex` + + ## Compiling Hopefully you don't need to do this, but if you have to, just take a look at `.github/workflows/main.yml` and you should be able to piece together how to get a compile working using CMake. You aren't required to download the devkit or set its path for CMake if you've got maya installed on your machine. Also note, I use features from CMake 3.16+ so I can target python 2 and 3 separately. diff --git a/simplex_maya_installer.py b/simplex_maya_installer.py new file mode 100644 index 0000000..43fbc16 --- /dev/null +++ b/simplex_maya_installer.py @@ -0,0 +1,201 @@ +import logging +import os +import sys +import zipfile +from pathlib import Path + +from maya import cmds, mel + +logging.basicConfig(level=logging.DEBUG) +logger = logging.getLogger(__name__) + + +sys.dont_write_bytecode = True + + +def install_numpy(pyexe, target): + """Install numpy to a particular folder + + Arguments: + pyexe (str|Path): A path to the current python executable + target (str|Path): The folder to install to + + Raises: + CalledProcessError: If the pip command fails + """ + import subprocess + + cmd = [str(pyexe), "-m", "pip", "install", "--target", str(target), "numpy"] + proc = subprocess.run( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + ) + + if proc.returncode != 0: + logging.critical("\n\n") + logging.critical(proc.stdout) + logging.critical("\n\n") + cmds.confirmDialog( + title="Simplex Install Error", + message="Numpy install failed", + button=["OK"], + ) + raise subprocess.CalledProcessError(proc.returncode, cmd, output=proc.stdout) + + +def get_latest_git_release(user, repo, asset_regex, out_path): + """Get the latest github release from a particular user/repo and download + it to a specified path + + Arguments: + user (str): The github user name to download from + repo (str): The github repo name to download + asset_regex (str): A regex to match against the name of the asset + out_path (str|Path): A filepath where the release should be downloaded to + + Returns: + Path: The path that the file was downloaded to. This *technically* may be + different from the provided out_path + + Raises: + ValueError: If the latest repo asset can't be found for download + """ + import json + import re + import urllib.request + + latest_link = f"https://api.github.com/repos/{user}/{repo}/releases/latest" + f = urllib.request.urlopen(latest_link) + latest_release_data = json.loads(f.read()) + assets = latest_release_data.get("assets", []) + download_url = None + for a in assets: + if re.match(asset_regex, a["name"]): + download_url = a["browser_download_url"] + break + + if download_url is None: + asset_names = "\n".join([a["name"] for a in assets]) + msg = f"regex: {asset_regex}\nnames:\n{asset_names}" + cmds.confirmDialog( + title="Simplex Install Error", + message="Release Download Failed", + button=["OK"], + ) + + raise ValueError( + f"Cannot find latest {user}/{repo} version to download.\nCheck your asset_regex\n{msg}" + ) + + out_path = Path(out_path) + outFolder = out_path.parent + outFolder.mkdir(exist_ok=True) + logger.info(f"Downloading latest simplex") + logger.info(f"from: {download_url}") + logger.info(f"to: {out_path}") + path, headers = urllib.request.urlretrieve(download_url, filename=out_path) + return Path(path) + + +def get_mayapy_path(): + """Get the path to the mayapy executable""" + binFolder = Path(sys.executable).parent + if sys.platform == "win32": + return binFolder / "mayapy.exe" + elif sys.platform == "darwin": + return binFolder / "mayapy" + elif sys.platform == "linux": + return binFolder / "mayapy" + cmds.confirmDialog( + title="Simplex Install Error", + message=f"Unsupported Platform: {sys.platform}", + button=["OK"], + ) + + raise RuntimeError(f"Current platform is unsupported: {sys.platform}") + + +def get_numpy_simplex_target(mod_folder): + """Get the target path for the numpy simplex install""" + + if sys.platform == "win32": + platform = "win64" + elif sys.platform == "darwin": + platform = "mac" + elif sys.platform == "linux": + platform = "linux" + else: + cmds.confirmDialog( + title="Simplex Install Error", + message=f"Unsupported Platform: {sys.platform}", + button=["OK"], + ) + raise RuntimeError(f"Current platform is unsupported: {sys.platform}") + + year = cmds.about(majorVersion=True) + nppath = mod_folder / "simplex" / f"{platform}-{year}" / "pyModules" + return nppath + + +def onMayaDroppedPythonFile(obj): + """This function will get run when you drag/drop this python script onto maya""" + try: + # Ensure that people will report a full error + cmds.optionVar(intValue=("stackTraceIsOn", 1)) + mel.eval('synchronizeScriptEditorOption(1, "StackTraceMenuItem")') + + mod_folder = Path(cmds.internalVar(uad=True)) / "modules" + modfile = mod_folder / "simplex.mod" + simplex_zip = mod_folder / "simplex.zip" + moddir = mod_folder / "simplex" + if modfile.is_file() != moddir.is_dir(): + msg = f"Simplex module is partially installed.\nPlease delete {modfile} and {moddir} and try again" + cmds.confirmDialog( + title="Simplex Install Error", + message=msg, + button=["OK"], + ) + raise ValueError(msg) + + if simplex_zip.is_file(): + os.remove(simplex_zip) + + # This will overwrite the existing install, but will leave any numpy installs alone + simplex_zip = get_latest_git_release( + "blurstudio", + "simplex", + r"simplex-v\d+\.\d+\.\d+\.zip", + simplex_zip, + ) + + if not simplex_zip.is_file(): + cmds.confirmDialog( + title="Simplex Install Error", + message="Zip file download failed", + button=["OK"], + ) + raise RuntimeError("Download of simplex zip failed") + + with zipfile.ZipFile(simplex_zip, "r") as zip_ref: + zip_ref.extractall(mod_folder) + os.remove(simplex_zip) + + try: + import numpy + except ModuleNotFoundError: + mayapy = get_mayapy_path() + target = get_numpy_simplex_target(mod_folder) + install_numpy(mayapy, target) + else: + logger.info("Numpy is already installed for this version of maya") + finally: + sys.dont_write_bytecode = False + + cmds.confirmDialog( + title="Simplex Installed", + message="Simplex installation complete", + button=["OK"], + ) +