- add model import via blender - add support dor 3ds, dae to SDK git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10237 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
f158717981
commit
74eccc7c8f
@ -0,0 +1,91 @@ |
|||||||
|
/* |
||||||
|
* To change this template, choose Tools | Templates |
||||||
|
* and open the template in the editor. |
||||||
|
*/ |
||||||
|
package com.jme3.gde.blender.filetypes; |
||||||
|
|
||||||
|
import com.jme3.gde.blender.BlenderTool; |
||||||
|
import com.jme3.gde.core.assets.ProjectAssetManager; |
||||||
|
import com.jme3.gde.core.assets.SpatialAssetDataObject; |
||||||
|
import com.jme3.scene.Spatial; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import org.openide.DialogDisplayer; |
||||||
|
import org.openide.NotifyDescriptor; |
||||||
|
import org.openide.filesystems.FileLock; |
||||||
|
import org.openide.filesystems.FileObject; |
||||||
|
import org.openide.filesystems.FileUtil; |
||||||
|
import org.openide.loaders.DataObjectExistsException; |
||||||
|
import org.openide.loaders.MultiFileLoader; |
||||||
|
import org.openide.util.Exceptions; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author normenhansen |
||||||
|
*/ |
||||||
|
public abstract class AbstractBlenderAssetDataObject extends SpatialAssetDataObject { |
||||||
|
|
||||||
|
protected String SUFFIX; |
||||||
|
|
||||||
|
public AbstractBlenderAssetDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { |
||||||
|
super(pf, loader); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Spatial loadAsset() { |
||||||
|
if (SUFFIX == null) { |
||||||
|
throw new IllegalStateException("Suffix for blender filetype is null! Set SUFFIX = \"sfx\" in constructor!"); |
||||||
|
} |
||||||
|
ProjectAssetManager mgr = getLookup().lookup(ProjectAssetManager.class); |
||||||
|
if (mgr == null) { |
||||||
|
DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("File is not part of a project!\nCannot load without ProjectAssetManager.")); |
||||||
|
return null; |
||||||
|
} |
||||||
|
FileObject mainFile = getPrimaryFile(); |
||||||
|
BlenderTool.runConversionScript(SUFFIX, mainFile); |
||||||
|
FileObject outFile = FileUtil.findBrother(mainFile, BlenderTool.TEMP_SUFFIX); |
||||||
|
if (outFile == null) { |
||||||
|
logger.log(Level.SEVERE, "Failed to create model, blend file cannot be found"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
String assetKey = mgr.getRelativeAssetPath(outFile.getPath()); |
||||||
|
FileLock lock = null; |
||||||
|
try { |
||||||
|
lock = getPrimaryFile().lock(); |
||||||
|
listListener.start(); |
||||||
|
Spatial spatial = mgr.loadModel(assetKey); |
||||||
|
replaceFiles(); |
||||||
|
listListener.stop(); |
||||||
|
savable = spatial; |
||||||
|
return spatial; |
||||||
|
} catch (IOException ex) { |
||||||
|
Exceptions.printStackTrace(ex); |
||||||
|
} finally { |
||||||
|
if (lock != null) { |
||||||
|
lock.releaseLock(); |
||||||
|
} |
||||||
|
try { |
||||||
|
outFile.delete(); |
||||||
|
} catch (IOException ex) { |
||||||
|
Exceptions.printStackTrace(ex); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
protected void replaceFiles() { |
||||||
|
for (int i = 0; i < assetList.size(); i++) { |
||||||
|
FileObject fileObject = assetList.get(i); |
||||||
|
if (fileObject.hasExt(BlenderTool.TEMP_SUFFIX)) { |
||||||
|
assetList.remove(i); |
||||||
|
assetKeyList.remove(i); |
||||||
|
assetList.add(i, getPrimaryFile()); |
||||||
|
assetKeyList.add(getAssetKey()); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
/* |
||||||
|
* To change this template, choose Tools | Templates |
||||||
|
* and open the template in the editor. |
||||||
|
*/ |
||||||
|
package com.jme3.gde.blender.filetypes; |
||||||
|
|
||||||
|
import com.jme3.gde.core.assets.SpatialAssetDataObject; |
||||||
|
import java.io.IOException; |
||||||
|
import org.openide.awt.ActionID; |
||||||
|
import org.openide.awt.ActionReference; |
||||||
|
import org.openide.awt.ActionReferences; |
||||||
|
import org.openide.filesystems.FileObject; |
||||||
|
import org.openide.filesystems.MIMEResolver; |
||||||
|
import org.openide.loaders.DataObject; |
||||||
|
import org.openide.loaders.DataObjectExistsException; |
||||||
|
import org.openide.loaders.MultiFileLoader; |
||||||
|
import org.openide.util.NbBundle.Messages; |
||||||
|
|
||||||
|
@Messages({ |
||||||
|
"LBL_Blender3ds_LOADER=3DS Files (via Blender)" |
||||||
|
}) |
||||||
|
@MIMEResolver.ExtensionRegistration( |
||||||
|
displayName = "#LBL_Blender3ds_LOADER", |
||||||
|
mimeType = "application/x-3ds", |
||||||
|
extension = {"3ds", "3DS"}) |
||||||
|
@DataObject.Registration( |
||||||
|
mimeType = "application/x-3ds", |
||||||
|
iconBase = "com/jme3/gde/blender/blender.png", |
||||||
|
displayName = "#LBL_Blender3ds_LOADER", |
||||||
|
position = 300) |
||||||
|
@ActionReferences({ |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.OpenAction"), |
||||||
|
position = 100, |
||||||
|
separatorAfter = 200), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "Edit", id = "org.openide.actions.CutAction"), |
||||||
|
position = 300), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), |
||||||
|
position = 400, |
||||||
|
separatorAfter = 500), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), |
||||||
|
position = 600), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.RenameAction"), |
||||||
|
position = 700, |
||||||
|
separatorAfter = 800), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), |
||||||
|
position = 900, |
||||||
|
separatorAfter = 1000), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), |
||||||
|
position = 1100, |
||||||
|
separatorAfter = 1200), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.ToolsAction"), |
||||||
|
position = 1300), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/application/x-3ds/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), |
||||||
|
position = 1400) |
||||||
|
}) |
||||||
|
public class Blender3dsDataObject extends AbstractBlenderAssetDataObject { |
||||||
|
|
||||||
|
public Blender3dsDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { |
||||||
|
super(pf, loader); |
||||||
|
SUFFIX = "3ds"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
/* |
||||||
|
* To change this template, choose Tools | Templates |
||||||
|
* and open the template in the editor. |
||||||
|
*/ |
||||||
|
package com.jme3.gde.blender.filetypes; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import org.openide.awt.ActionID; |
||||||
|
import org.openide.awt.ActionReference; |
||||||
|
import org.openide.awt.ActionReferences; |
||||||
|
import org.openide.filesystems.FileObject; |
||||||
|
import org.openide.filesystems.MIMEResolver; |
||||||
|
import org.openide.loaders.DataObject; |
||||||
|
import org.openide.loaders.DataObjectExistsException; |
||||||
|
import org.openide.loaders.MultiFileLoader; |
||||||
|
import org.openide.util.NbBundle.Messages; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author normenhansen |
||||||
|
*/ |
||||||
|
@Messages({ |
||||||
|
"LBL_BlenderDae_LOADER=Collada Files (via Blender)" |
||||||
|
}) |
||||||
|
@MIMEResolver.ExtensionRegistration( |
||||||
|
displayName = "#LBL_BlenderDae_LOADER", |
||||||
|
mimeType = "model/vnd.collada+xml", |
||||||
|
extension = {"dae", "DAE"}) |
||||||
|
@DataObject.Registration( |
||||||
|
mimeType = "model/vnd.collada+xml", |
||||||
|
iconBase = "com/jme3/gde/blender/blender.png", |
||||||
|
displayName = "#LBL_BlenderDae_LOADER", |
||||||
|
position = 300) |
||||||
|
@ActionReferences({ |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.OpenAction"), |
||||||
|
position = 100, |
||||||
|
separatorAfter = 200), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "Edit", id = "org.openide.actions.CutAction"), |
||||||
|
position = 300), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), |
||||||
|
position = 400, |
||||||
|
separatorAfter = 500), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), |
||||||
|
position = 600), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.RenameAction"), |
||||||
|
position = 700, |
||||||
|
separatorAfter = 800), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), |
||||||
|
position = 900, |
||||||
|
separatorAfter = 1000), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), |
||||||
|
position = 1100, |
||||||
|
separatorAfter = 1200), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.ToolsAction"), |
||||||
|
position = 1300), |
||||||
|
@ActionReference( |
||||||
|
path = "Loaders/model/vnd.collada+xml/Actions", |
||||||
|
id = |
||||||
|
@ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), |
||||||
|
position = 1400) |
||||||
|
}) |
||||||
|
public class BlenderDaeDataObject extends AbstractBlenderAssetDataObject { |
||||||
|
|
||||||
|
public BlenderDaeDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { |
||||||
|
super(pf, loader); |
||||||
|
SUFFIX = "dae"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
/* |
||||||
|
* To change this template, choose Tools | Templates |
||||||
|
* and open the template in the editor. |
||||||
|
*/ |
||||||
|
package com.jme3.gde.blender.scripts; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.io.OutputStream; |
||||||
|
import java.net.URL; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.openide.filesystems.FileObject; |
||||||
|
import org.openide.filesystems.FileUtil; |
||||||
|
import org.openide.util.Exceptions; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author normenhansen |
||||||
|
*/ |
||||||
|
public class Scripts { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(Scripts.class.getName()); |
||||||
|
private final static String root = "com/jme3/gde/blender/scripts/"; |
||||||
|
|
||||||
|
public static void copyToFolder(FileObject folder) { |
||||||
|
if (folder == null) { |
||||||
|
logger.log(Level.WARNING, "Got null folder for scripts check"); |
||||||
|
return; |
||||||
|
} |
||||||
|
checkScript(folder, "import_3ds.py"); |
||||||
|
checkScript(folder, "import_dae.py"); |
||||||
|
} |
||||||
|
|
||||||
|
private static void checkScript(FileObject folder, String name) { |
||||||
|
FileObject file = folder.getFileObject(name); |
||||||
|
//TODO:check version!
|
||||||
|
if (file == null) { |
||||||
|
try { |
||||||
|
InputStream in = null; |
||||||
|
OutputStream out = null; |
||||||
|
try { |
||||||
|
URL url = new URL("nbres:" + root + name); |
||||||
|
file = FileUtil.createData(folder, name); |
||||||
|
in = url.openStream(); |
||||||
|
out = file.getOutputStream(); |
||||||
|
FileUtil.copy(in, out); |
||||||
|
} catch (IOException e) { |
||||||
|
Exceptions.printStackTrace(e); |
||||||
|
} finally { |
||||||
|
if (in != null) { |
||||||
|
in.close(); |
||||||
|
} |
||||||
|
if (out != null) { |
||||||
|
out.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
logger.log(Level.INFO, "Extracted script {0}", file.getPath()); |
||||||
|
} catch (IOException ex) { |
||||||
|
Exceptions.printStackTrace(ex); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
# This script is an example of how you can run blender from the command line |
||||||
|
# (in background mode with no interface) to automate tasks, in this example it |
||||||
|
# creates a text object, camera and light, then renders and/or saves it. |
||||||
|
# This example also shows how you can parse command line options to scripts. |
||||||
|
# |
||||||
|
# Example usage for this test. |
||||||
|
# blender --background --factory-startup --python $HOME/background_job.py -- \ |
||||||
|
# --text="Hello World" \ |
||||||
|
# --render="/tmp/hello" \ |
||||||
|
# --save="/tmp/hello.blend" |
||||||
|
# |
||||||
|
# Notice: |
||||||
|
# '--factory-startup' is used to avoid the user default settings from |
||||||
|
# interfearing with automated scene generation. |
||||||
|
# |
||||||
|
# '--' causes blender to ignore all following arguments so python can use them. |
||||||
|
# |
||||||
|
# See blender --help for details. |
||||||
|
|
||||||
|
import bpy |
||||||
|
|
||||||
|
|
||||||
|
def convert_file(file_path, save_path): |
||||||
|
bpy.ops.import_scene.autodesk_3ds(filepath = file_path) |
||||||
|
|
||||||
|
scene = bpy.context.scene |
||||||
|
|
||||||
|
try: |
||||||
|
f = open(save_path, 'w') |
||||||
|
f.close() |
||||||
|
ok = True |
||||||
|
except: |
||||||
|
print("Cannot save to path %r" % save_path) |
||||||
|
|
||||||
|
import traceback |
||||||
|
traceback.print_exc() |
||||||
|
|
||||||
|
if ok: |
||||||
|
bpy.ops.wm.save_as_mainfile(filepath=save_path) |
||||||
|
|
||||||
|
def main(): |
||||||
|
import sys # to get command line args |
||||||
|
import argparse # to parse options for us and print a nice help message |
||||||
|
|
||||||
|
# get the args passed to blender after "--", all of which are ignored by |
||||||
|
# blender so scripts may receive their own arguments |
||||||
|
argv = sys.argv |
||||||
|
|
||||||
|
if "--" not in argv: |
||||||
|
argv = [] # as if no args are passed |
||||||
|
else: |
||||||
|
argv = argv[argv.index("--") + 1:] # get all args after "--" |
||||||
|
|
||||||
|
# When --help or no args are given, print this help |
||||||
|
usage_text = \ |
||||||
|
"Run blender in background mode with this script:" |
||||||
|
" blender --background --factory-startup --python " + __file__ + " -- [options]" |
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=usage_text) |
||||||
|
|
||||||
|
# Possible types are: string, int, long, choice, float and complex. |
||||||
|
parser.add_argument("-i", "--input", dest="file_path", metavar='FILE', |
||||||
|
help="Import the specified file") |
||||||
|
parser.add_argument("-o", "--output", dest="save_path", metavar='FILE', |
||||||
|
help="Save the generated file to the specified path") |
||||||
|
|
||||||
|
args = parser.parse_args(argv) # In this example we wont use the args |
||||||
|
|
||||||
|
if not argv: |
||||||
|
parser.print_help() |
||||||
|
return |
||||||
|
|
||||||
|
# Clear existing objects. |
||||||
|
scene = bpy.context.scene |
||||||
|
scene.camera = None |
||||||
|
for obj in scene.objects: |
||||||
|
scene.objects.unlink(obj) |
||||||
|
|
||||||
|
# Run the conversion |
||||||
|
convert_file(args.file_path, args.save_path) |
||||||
|
|
||||||
|
print("batch job finished, exiting") |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
@ -0,0 +1,86 @@ |
|||||||
|
# This script is an example of how you can run blender from the command line |
||||||
|
# (in background mode with no interface) to automate tasks, in this example it |
||||||
|
# creates a text object, camera and light, then renders and/or saves it. |
||||||
|
# This example also shows how you can parse command line options to scripts. |
||||||
|
# |
||||||
|
# Example usage for this test. |
||||||
|
# blender --background --factory-startup --python $HOME/background_job.py -- \ |
||||||
|
# --text="Hello World" \ |
||||||
|
# --render="/tmp/hello" \ |
||||||
|
# --save="/tmp/hello.blend" |
||||||
|
# |
||||||
|
# Notice: |
||||||
|
# '--factory-startup' is used to avoid the user default settings from |
||||||
|
# interfearing with automated scene generation. |
||||||
|
# |
||||||
|
# '--' causes blender to ignore all following arguments so python can use them. |
||||||
|
# |
||||||
|
# See blender --help for details. |
||||||
|
|
||||||
|
import bpy |
||||||
|
|
||||||
|
|
||||||
|
def convert_file(file_path, save_path): |
||||||
|
bpy.ops.wm.collada_import(filepath = file_path) |
||||||
|
|
||||||
|
scene = bpy.context.scene |
||||||
|
|
||||||
|
try: |
||||||
|
f = open(save_path, 'w') |
||||||
|
f.close() |
||||||
|
ok = True |
||||||
|
except: |
||||||
|
print("Cannot save to path %r" % save_path) |
||||||
|
|
||||||
|
import traceback |
||||||
|
traceback.print_exc() |
||||||
|
|
||||||
|
if ok: |
||||||
|
bpy.ops.wm.save_as_mainfile(filepath=save_path) |
||||||
|
|
||||||
|
def main(): |
||||||
|
import sys # to get command line args |
||||||
|
import argparse # to parse options for us and print a nice help message |
||||||
|
|
||||||
|
# get the args passed to blender after "--", all of which are ignored by |
||||||
|
# blender so scripts may receive their own arguments |
||||||
|
argv = sys.argv |
||||||
|
|
||||||
|
if "--" not in argv: |
||||||
|
argv = [] # as if no args are passed |
||||||
|
else: |
||||||
|
argv = argv[argv.index("--") + 1:] # get all args after "--" |
||||||
|
|
||||||
|
# When --help or no args are given, print this help |
||||||
|
usage_text = \ |
||||||
|
"Run blender in background mode with this script:" |
||||||
|
" blender --background --python " + __file__ + " -- [options]" |
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=usage_text) |
||||||
|
|
||||||
|
# Possible types are: string, int, long, choice, float and complex. |
||||||
|
parser.add_argument("-i", "--input", dest="file_path", metavar='FILE', |
||||||
|
help="Import the specified file") |
||||||
|
parser.add_argument("-o", "--output", dest="save_path", metavar='FILE', |
||||||
|
help="Save the generated file to the specified path") |
||||||
|
|
||||||
|
args = parser.parse_args(argv) # In this example we wont use the args |
||||||
|
|
||||||
|
if not argv: |
||||||
|
parser.print_help() |
||||||
|
return |
||||||
|
|
||||||
|
# Clear existing objects. |
||||||
|
scene = bpy.context.scene |
||||||
|
scene.camera = None |
||||||
|
for obj in scene.objects: |
||||||
|
scene.objects.unlink(obj) |
||||||
|
|
||||||
|
# Run the conversion |
||||||
|
convert_file(args.file_path, args.save_path) |
||||||
|
|
||||||
|
print("batch job finished, exiting") |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
Loading…
Reference in new issue