diff --git a/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java b/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java index 0929c37a8..4f7c10494 100644 --- a/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java +++ b/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java @@ -1,6 +1,118 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + Blender Options: + -b or --background Load in background (often used for UI-less rendering) + -a or --render-anim Render frames from start to end (inclusive) + -S or --scene Set the active scene for rendering + -f or --render-frame Render frame and save it. + start frame relative, - end frame relative. + -s or --frame-start Set start to frame (use before the -a argument) + -e or --frame-end Set end to frame (use before the -a argument) + -j or --frame-jump Set number of frames to step forward after each rendered frame + -o or --render-output Set the render path and file name. Use // at the start of the path to + render relative to the blend file. The # characters are replaced by the frame number, and used to define zero padding. + ani_##_test.png becomes ani_01_test.png + test-######.png becomes test-000001.png + When the filename does not contain #, The suffix #### is added to the filename The frame number will be added at the end of the filename. + eg: blender -b foobar.blend -o //render_ -F PNG -x 1 -a + //render_ becomes //render_####, writing frames as //render_0001.png// + -E or --engine Specify the render engine use -E help to list available engines + + Format Options: + -F or --render-format Set the render format, Valid options are... + TGA IRIS JPEG MOVIE IRIZ RAWTGA + AVIRAW AVIJPEG PNG BMP FRAMESERVER (formats that can be compiled into blender, not available on all systems) + HDR TIFF EXR MULTILAYER MPEG AVICODEC QUICKTIME CINEON DPX DDS + -x or --use-extension Set option to add the file extension to the end of the file + -t or --threads Use amount of for rendering in background [1-64], 0 for systems processor count. + + Animation Playback Options: + -a Playback , only operates this way when not running in background. + -p Open with lower left corner at , + -m Read from disk (Don't buffer) + -f Specify FPS to start with + -j Set frame step to + + Window Options: + -w or --window-border Force opening with borders (default) + -W or --window-borderless Force opening without borders + -p or --window-geometry Open with lower left corner at , and width and height as , + -con or --start-console Start with the console window open (ignored if -b is set) + + Game Engine Specific Options: + -g Game Engine specific options + -g fixedtime Run on 50 hertz without dropping frames + -g vertexarrays Use Vertex Arrays for rendering (usually faster) + -g nomipmap No Texture Mipmapping + -g linearmipmap Linear Texture Mipmapping instead of Nearest (default) + + Misc Options: + -d or --debug Turn debugging on + * Prints every operator call and their arguments + * Disables mouse grab (to interact with a debugger in some cases) + * Keeps python sys.stdin rather than setting it to None + --debug-fpe Enable floating point exceptions + --debug-ffmpeg Enable debug messages from FFmpeg library + --debug-libmv Enable debug messages from libmv library + + --factory-startup Skip reading the "startup.blend" in the users home directory + + --env-system-datafiles Set the BLENDER_SYSTEM_DATAFILES environment variable + --env-system-scripts Set the BLENDER_SYSTEM_SCRIPTS environment variable + --env-system-python Set the BLENDER_SYSTEM_PYTHON environment variable + + -nojoystick Disable joystick support + -noglsl Disable GLSL shading + -noaudio Force sound system to None + -setaudio Force sound system to a specific device NULL SDL OPENAL JACK + + -h or --help Print this help text and exit + + -y or --enable-autoexec Enable automatic python script execution, (default) + -Y or --disable-autoexec Disable automatic python script execution (pydrivers & startup scripts) + + -P or --python Run the given Python script (filename or Blender Text) + --python-console Run blender with an interactive console + --addons Comma separated list of addons (no spaces) + -v or --version Print Blender version and exit + -- Ends option processing, following arguments passed unchanged. Access via python's sys.argv + Other Options: + /? Print this help text and exit (windows only) + --debug-python Enable debug messages for python + --debug-events Enable debug messages for the event system + --debug-wm Enable debug messages for the window manager + --debug-all Enable all debug messages (excludes libmv) + --debug-value Set debug value of on startup + + --debug-jobs Enable time profiling for background jobs. + --verbose Set logging verbosity level. + -R Register .blend extension, then exit (Windows only) + -r Silently register .blend extension, then exit (Windows only) + Argument Parsing: arguments must be separated by white space. eg + "blender -ba test.blend" + ...will ignore the 'a' + "blender -b test.blend -f8" + ...will ignore 8 because there is no space between the -f and the frame value + Argument Order: + Arguments are executed in the order they are given. eg + "blender --background test.blend --render-frame 1 --render-output /tmp" + ...will not render to /tmp because '--render-frame 1' renders before the output path is set + "blender --background --render-output /tmp test.blend --render-frame 1" + ...will not render to /tmp because loading the blend file overwrites the render output that was set + "blender --background test.blend --render-output /tmp --render-frame 1" works as expected. + + Environment Variables: + $BLENDER_USER_CONFIG Directory for user configuration files. + $BLENDER_USER_SCRIPTS Directory for user scripts. + $BLENDER_SYSTEM_SCRIPTS Directory for system wide scripts. + $Directory for user data files (icons, translations, ..). + $BLENDER_SYSTEM_DATAFILES Directory for system wide data files. + $BLENDER_SYSTEM_PYTHON Directory for system python libraries. + $TMP or $TMPDIR Store temporary files here. + $SDL_AUDIODRIVER LibSDL audio driver - alsa, esd, dma. + $PYTHONHOME Path to the python directory, eg. /usr/lib/python. + + blender/config + blender/scripts + blender/userscripts */ package com.jme3.gde.blender; @@ -14,17 +126,24 @@ import java.util.logging.Logger; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; import org.openide.modules.InstalledFileLocator; import org.openide.util.Exceptions; import org.openide.util.Utilities; import org.openide.windows.WindowManager; - +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; /** * * @author normenhansen */ public class BlenderTool { + private static final String mainFolderName = "blender"; + private static final String configFolderName = mainFolderName + "/config"; + private static final String scriptsFolderName = mainFolderName + "/scripts"; + private static final String userScriptsFolderName = mainFolderName + "/userscripts"; + private static final String tempFolderName = mainFolderName + "/temp"; private static final Logger logger = Logger.getLogger(BlenderTool.class.getName()); private static boolean running = false; private static Window blenderWindow = null; @@ -37,58 +156,109 @@ public class BlenderTool { } } - public static File getBlenderExecutable() { - File blender = InstalledFileLocator.getDefault().locate("../blender/" + getBlenderExeName(), null, false); - if (blender == null) { - DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Error finding Blender executable at\n" + blender.getPath())); - logger.log(Level.SEVERE, "Error finding Blender executable at {0}", blender.getPath()); + private static String getBlenderOsPath() { + if (Utilities.isMac()) { + return "../blender/blender.app/Contents/MacOS"; + } else { + return "../blender"; } - return blender; } - public static File getBlenderSettingsFolder() { - File blender = InstalledFileLocator.getDefault().locate("../blender/2.64", null, false); + private static boolean checkBlenderFolders() { + String jmpDir = System.getProperty("netbeans.user"); + FileObject fileObject = FileUtil.toFileObject(new File(jmpDir)); + if (fileObject != null) { + FileObject configFileObject = fileObject.getFileObject(configFolderName); + //TODO: using installed blender scripts folder, make more flexible by moving + //to updateable folder +// FileObject scriptsFileObject = fileObject.getFileObject(scriptsFolderName); + FileObject userScriptsFileObject = fileObject.getFileObject(userScriptsFolderName); + if (configFileObject == null) { + try { + FileUtil.createFolder(fileObject, configFolderName); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + return false; + } + } +// if (scriptsFileObject == null) { +// try { +// FileUtil.createFolder(fileObject, scriptsFolderName); +// } catch (IOException ex) { +// Exceptions.printStackTrace(ex); +// return false; +// } +// } + if (userScriptsFileObject == null) { + try { + FileUtil.createFolder(fileObject, userScriptsFolderName); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + return false; + } + } + } else { + logger.log(Level.SEVERE, "No global settings folder found!"); + return false; + } + return true; + } + + private static String getConfigEnv() { + String ret = System.getProperty("netbeans.user") + "/" + configFolderName; + ret = ret.replace("/", File.separator); + return ret; + } + + private static String getScriptsEnv() { + //TODO: using installed blender scripts folder + String ret = getBlenderSettingsFolder().getAbsolutePath(); +// String ret = System.getProperty("netbeans.user") + "/" + scriptsFolderName; + ret = ret.replace("/", File.separator); + return ret; + } + + private static String getUserScriptsEnv() { + String ret = System.getProperty("netbeans.user") + "/" + userScriptsFolderName; + ret = ret.replace("/", File.separator); + return ret; + } + + private static File getBlenderExecutable() { + File blender = InstalledFileLocator.getDefault().locate(getBlenderOsPath() + "/" + getBlenderExeName(), null, false); if (blender == null) { - DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Error finding Blender settings at\n" + blender.getPath())); - logger.log(Level.SEVERE, "Error finding Blender settings at {0}", blender.getPath()); + DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Error finding Blender executable")); + logger.log(Level.SEVERE, "Error finding Blender executable"); } return blender; } - public static File getBlenderRootFolder() { -// File appFolder = InstalledFileLocator.getDefault().locate("bin", null, false).getParentFile().getParentFile(); -// if (appFolder != null) { -// DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(appFolder.toString())); -// } - File blender = InstalledFileLocator.getDefault().locate("../blender", null, false); + private static File getBlenderSettingsFolder() { + File blender = InstalledFileLocator.getDefault().locate(getBlenderOsPath() + "/2.64", null, false); if (blender == null) { - DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Error finding Blender root folder at\n" + blender.getPath())); - logger.log(Level.SEVERE, "Error finding Blender root folder at {0}", blender.getPath()); + DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Error finding Blender settings")); + logger.log(Level.SEVERE, "Error finding Blender settings"); } return blender; - } - public static boolean openInBlender(FileObject file) { - String path = file.getPath().replace("/", File.separator); - return runBlender(path, true); + private static File getBlenderRootFolder() { + File blender = InstalledFileLocator.getDefault().locate(getBlenderOsPath(), null, false); + if (blender == null) { + DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Error finding Blender root folder")); + logger.log(Level.SEVERE, "Error finding Blender root folder"); + } + return blender; } private static void setBlendWin(Window win) { blenderWindow = win; } - public static boolean blenderToFront() { - Window win = blenderWindow; - if (win != null) { - logger.log(Level.INFO, "Request focus of Blender window {0}", win); - win.requestFocus(); - return true; + private static boolean runBlender(final String options, boolean async) { + if (!checkBlenderFolders()) { + logger.log(Level.SEVERE, "Could not create blender settings folders!"); } - return false; - } - - public static boolean runBlender(final String options, boolean async) { logger.log(Level.INFO, "Try running blender with options {0}", options); if (running) { logger.log(Level.INFO, "Blender seems to be running"); @@ -123,13 +293,13 @@ public class BlenderTool { Runnable r = new Runnable() { public void run() { try { - String command = null; - if (options != null) { - command = exe.getAbsolutePath() + " " + options; - } else { - command = exe.getAbsolutePath(); - } - Process proc = Runtime.getRuntime().exec(command); + String command = exe.getAbsolutePath(); + ProcessBuilder buildr = new ProcessBuilder(command, options); + buildr.directory(getBlenderRootFolder()); + buildr.environment().put("BLENDER_USER_CONFIG", getConfigEnv()); + buildr.environment().put("BLENDER_SYSTEM_SCRIPTS", getScriptsEnv()); + buildr.environment().put("BLENDER_USER_SCRIPTS", getUserScriptsEnv()); + Process proc = buildr.start(); OutputReader outReader = new OutputReader(proc.getInputStream()); OutputReader errReader = new OutputReader(proc.getErrorStream()); outReader.start(); @@ -174,6 +344,21 @@ public class BlenderTool { } } + public static boolean openInBlender(FileObject file) { + String path = "'" + file.getPath().replace("/", File.separator) + "'"; + return runBlender(path, true); + } + + public static boolean blenderToFront() { + Window win = blenderWindow; + if (win != null) { + logger.log(Level.INFO, "Request focus of Blender window {0}", win); + win.requestFocus(); + return true; + } + return false; + } + public static void runBlender() { if (!runBlender(null, true)) { logger.log(Level.INFO, "Could not run blender, already running? Trying to focus window.");