|
|
|
@ -1,6 +1,118 @@ |
|
|
|
|
/* |
|
|
|
|
* To change this template, choose Tools | Templates |
|
|
|
|
* and open the template in the editor. |
|
|
|
|
Blender Options: |
|
|
|
|
-b or --background <file> Load <file> in background (often used for UI-less rendering) |
|
|
|
|
-a or --render-anim Render frames from start to end (inclusive) |
|
|
|
|
-S or --scene <name> Set the active scene <name> for rendering |
|
|
|
|
-f or --render-frame <frame> Render frame <frame> and save it. +<frame> start frame relative, -<frame> end frame relative. |
|
|
|
|
-s or --frame-start <frame> Set start to frame <frame> (use before the -a argument) |
|
|
|
|
-e or --frame-end <frame> Set end to frame <frame> (use before the -a argument) |
|
|
|
|
-j or --frame-jump <frames> Set number of frames to step forward after each rendered frame |
|
|
|
|
-o or --render-output <path> 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 <engine> Specify the render engine use -E help to list available engines |
|
|
|
|
|
|
|
|
|
Format Options: |
|
|
|
|
-F or --render-format <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 <bool> Set option to add the file extension to the end of the file |
|
|
|
|
-t or --threads <threads> Use amount of <threads> for rendering in background [1-64], 0 for systems processor count. |
|
|
|
|
|
|
|
|
|
Animation Playback Options: |
|
|
|
|
-a <options> <file(s)> Playback <file(s)>, only operates this way when not running in background. |
|
|
|
|
-p <sx> <sy> Open with lower left corner at <sx>, <sy> |
|
|
|
|
-m Read from disk (Don't buffer) |
|
|
|
|
-f <fps> <fps-base> Specify FPS to start with |
|
|
|
|
-j <frame> Set frame step to <frame> |
|
|
|
|
|
|
|
|
|
Window Options: |
|
|
|
|
-w or --window-border Force opening with borders (default) |
|
|
|
|
-W or --window-borderless Force opening without borders |
|
|
|
|
-p or --window-geometry <sx> <sy> <w> <h> Open with lower left corner at <sx>, <sy> and width and height as <w>, <h> |
|
|
|
|
-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 <filename> 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 <value> Set debug value of <value> on startup |
|
|
|
|
|
|
|
|
|
--debug-jobs Enable time profiling for background jobs. |
|
|
|
|
--verbose <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."); |
|
|
|
|