diff --git a/jme3-blender/build.xml b/jme3-blender/build.xml new file mode 100644 index 000000000..535b63fb0 --- /dev/null +++ b/jme3-blender/build.xml @@ -0,0 +1,8 @@ + + + + + + Builds, tests, and runs the project com.jme3.gde.blender. + + diff --git a/jme3-blender/manifest.mf b/jme3-blender/manifest.mf new file mode 100644 index 000000000..3e10413d0 --- /dev/null +++ b/jme3-blender/manifest.mf @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +OpenIDE-Module: com.jme3.gde.blender +OpenIDE-Module-Implementation-Version: 0 +OpenIDE-Module-Localizing-Bundle: com/jme3/gde/blender/Bundle.properties + diff --git a/jme3-blender/nbproject/build-impl.xml b/jme3-blender/nbproject/build-impl.xml new file mode 100644 index 000000000..7232c5d6f --- /dev/null +++ b/jme3-blender/nbproject/build-impl.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + You must set 'suite.dir' to point to your containing module suite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jme3-blender/nbproject/genfiles.properties b/jme3-blender/nbproject/genfiles.properties new file mode 100644 index 000000000..3f9c08a70 --- /dev/null +++ b/jme3-blender/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=46157a9c +build.xml.script.CRC32=0f77a514 +build.xml.stylesheet.CRC32=15ca8a54@2.79 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=46157a9c +nbproject/build-impl.xml.script.CRC32=5c5042d6 +nbproject/build-impl.xml.stylesheet.CRC32=49aa68b0@2.79 diff --git a/jme3-blender/nbproject/project.properties b/jme3-blender/nbproject/project.properties new file mode 100644 index 000000000..c67aa1b97 --- /dev/null +++ b/jme3-blender/nbproject/project.properties @@ -0,0 +1,8 @@ +#Thu, 25 Aug 2011 20:26:50 +0200 +javac.source=21 +javac.compilerargs=-Xlint -Xlint\:-serial +license.file=../license-jme.txt +nbm.homepage=https://www.jmonkeyengine.org +nbm.module.author=Kaelthas +nbm.needs.restart=true +spec.version.base=3.5.2 diff --git a/jme3-blender/nbproject/project.xml b/jme3-blender/nbproject/project.xml new file mode 100644 index 000000000..f9dc8f1ee --- /dev/null +++ b/jme3-blender/nbproject/project.xml @@ -0,0 +1,173 @@ + + + org.netbeans.modules.apisupport.project + + + com.jme3.gde.blender + + + + com.jme3.gde.core + + + + 1 + 3.6.1 + + + + com.jme3.gde.core.baselibs + + + + 1 + 3.6.1 + + + + com.jme3.gde.core.libraries + + + + 1 + 3.6.1 + + + + org.netbeans.api.progress + + + + 1 + 1.46.1 + + + + org.netbeans.api.progress.nb + + + + 1.46.1 + + + + org.netbeans.api.templates + + + + 1.6.1 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.60.2 + + + + org.netbeans.modules.websvc.jaxws21api + + + + 1 + 1.34.1 + + + + org.openide.awt + + + + 7.62.1 + + + + org.openide.dialogs + + + + 7.38.1 + + + + org.openide.filesystems + + + + 9.7.1 + + + + org.openide.filesystems.nb + + + + 9.7.1 + + + + org.openide.loaders + + + + 7.57.2 + + + + org.openide.modules + + + + 7.43.1 + + + + org.openide.nodes + + + + 7.39.1 + + + + org.openide.util + + + + 8.39.1 + + + + org.openide.util.lookup + + + + 8.25.1 + + + + org.openide.util.ui + + + + 9.4.1 + + + + org.openide.windows + + + + 6.71.1 + + + + + com.jme3.gde.blender + + + + diff --git a/jme3-blender/nbproject/suite.properties b/jme3-blender/nbproject/suite.properties new file mode 100644 index 000000000..29d7cc9bd --- /dev/null +++ b/jme3-blender/nbproject/suite.properties @@ -0,0 +1 @@ +suite.dir=${basedir}/.. diff --git a/jme3-blender/src/com/jme3/gde/blender/Bundle.properties b/jme3-blender/src/com/jme3/gde/blender/Bundle.properties new file mode 100644 index 000000000..8ecfde7d0 --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/Bundle.properties @@ -0,0 +1,5 @@ +OpenIDE-Module-Display-Category=jMonkeyEngine +OpenIDE-Module-Long-Description=\ + This plugin adds support for GLTF's .gltf .glb and .bin files +OpenIDE-Module-Name=GLTF Support +OpenIDE-Module-Short-Description=Adds support for GLTF's .gltf .glb and .bin files \ No newline at end of file diff --git a/jme3-blender/src/com/jme3/gde/blender/GLTFDataObject.java b/jme3-blender/src/com/jme3/gde/blender/GLTFDataObject.java new file mode 100644 index 000000000..a428f26aa --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/GLTFDataObject.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009-2020 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.blender; + +import com.jme3.asset.ModelKey; +import com.jme3.gde.core.assets.SpatialAssetDataObject; +import com.jme3.scene.plugins.gltf.GltfModelKey; +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_GLTF_LOADER=GLTF Files" +}) +@MIMEResolver.ExtensionRegistration( + displayName="#LBL_GLTF_LOADER", + mimeType="model/gltf+json", + //mimeType="model/gltf-binary", + // glb has another mimeType but for us, this is irrelevant. The Actions are the same + extension={ "gltf", "glb" } +) +@DataObject.Registration( + mimeType = "model/gltf+json", + iconBase = "com/jme3/gde/blender/glTF.svg", + displayName="#LBL_GLTF_LOADER", + position=300 +) +@ActionReferences(value = { + @ActionReference(id = + @ActionID(category = "jMonkeyPlatform", id = "com.jme3.gde.core.assets.actions.ConvertModel"), path = "Loaders/model/gltf+json/Actions", position = 10), + @ActionReference(id = + @ActionID(category = "jMonkeyPlatform", id = "com.jme3.gde.core.assets.actions.OpenModel"), path = "Loaders/model/gltf+json/Actions", position = 20), + @ActionReference(id = + @ActionID(category = "Edit", id = "org.openide.actions.CutAction"), path = "Loaders/model/gltf+json/Actions", position = 200, separatorBefore = 100), + @ActionReference(id = + @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), path = "Loaders/model/gltf+json/Actions", position = 300, separatorAfter = 400), + @ActionReference(id = + @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), path = "Loaders/model/gltf+json/Actions", position = 500), + @ActionReference(id = + @ActionID(category = "System", id = "org.openide.actions.RenameAction"), path = "Loaders/model/gltf+json/Actions", position = 600, separatorAfter = 700), + @ActionReference(id = + @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), path = "Loaders/model/gltf+json/Actions", position = 800, separatorAfter = 900), + @ActionReference(id = + @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), path = "Loaders/model/gltf+json/Actions", position = 1000, separatorAfter = 1100), + @ActionReference(id = + @ActionID(category = "System", id = "org.openide.actions.ToolsAction"), path = "Loaders/model/gltf+json/Actions", position = 1200), + @ActionReference(id = + @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), path = "Loaders/model/gltf+json/Actions", position = 1300) +}) + +/** + * This class enables the SDK to open and convert .gltf and + * glb files. + * + * @author MeFisto94 + */ +public class GLTFDataObject extends SpatialAssetDataObject { + public GLTFDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { + super(pf, loader); + } + + @Override + public synchronized ModelKey getAssetKey() { + GltfModelKey gltf = new GltfModelKey(super.getAssetKey().getName()); + gltf.setExtrasLoader(GltfExtrasLoader.INSTANCE); + return gltf; + } + +} diff --git a/jme3-blender/src/com/jme3/gde/blender/GltfExtrasLoader.java b/jme3-blender/src/com/jme3/gde/blender/GltfExtrasLoader.java new file mode 100644 index 000000000..a4ddbf7e3 --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/GltfExtrasLoader.java @@ -0,0 +1,199 @@ +/* + * $Id$ + * + * Copyright (c) 2019, Simsilica, LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.gde.blender; + +import com.jme3.plugins.json.JsonArray; +import com.jme3.plugins.json.JsonElement; +import com.jme3.plugins.json.JsonObject; +import com.jme3.plugins.json.JsonPrimitive; +import java.lang.reflect.Array; +import java.util.*; + +import org.slf4j.*; + +import com.jme3.scene.Spatial; +import com.jme3.scene.plugins.gltf.*; + +/** + * Attaches GLTF "extras" data to objects as appropriate.
+ * Note: Taken by MeFisto94 and modified to match for the SDK. + * + * @author Paul Speed + */ +public class GltfExtrasLoader implements ExtrasLoader { + static Logger log = LoggerFactory.getLogger(GltfExtrasLoader.class); + + public static final GltfExtrasLoader INSTANCE = new GltfExtrasLoader(); + + public GltfExtrasLoader() { + } + + /** + * Utility method to create a ModelKey that is configured to use this + * ExtrasLoader. + */ + public static GltfModelKey createModelKey( String path ) { + GltfModelKey key = new GltfModelKey(path); + key.setExtrasLoader(INSTANCE); + return key; + } + + @Override + public Object handleExtras( GltfLoader loader, String parentName, + JsonElement parent, JsonElement extras, Object input ) { + + log.debug("handleExtras(" + loader + ", " + parentName + ", " + parent + ", " + extras + ", " + input + ")"); + + // Only interested in composite objects + JsonObject jo = null; + try { + jo = extras.getAsJsonObject(); + } + catch(Exception e) { + log.warn("Skipping extras:" + extras, e); + } + + if(jo == null) { + log.warn("Skipping extras:" + extras); + return input; + } + + apply(input, jo); + return input; + } + + protected void apply( Object input, JsonObject extras ) { + if( input == null ) { + return; + } + if( input.getClass().isArray() ) { + applyToArray(input, extras); + } else if( input instanceof Spatial ) { + applyToSpatial((Spatial)input, extras); + } else { + log.warn("Unhandled input type:" + input.getClass()); + } + } + + protected void applyToArray( Object array, JsonObject extras ) { + int size = Array.getLength(array); + for( int i = 0; i < size; i++ ) { + Object o = Array.get(array, i); + log.debug("processing array[" + i + "]:" + o); + apply(o, extras); + } + } + + protected void applyToSpatial( Spatial spatial, JsonObject extras ) { + for( Map.Entry el : extras.entrySet() ) { + log.debug(el.toString()); + Object val = toAttribute(el.getValue(), false); + if( log.isDebugEnabled() ) { + log.debug("setUserData(" + el.getKey() + ", " + val + ")"); + } + spatial.setUserData(el.getKey(), val); + } + } + + protected Object toAttribute( JsonElement el, boolean nested ) { + try { + return toAttribute(el.getAsJsonObject(), nested); + } catch (Exception e) { + } + + try { + return toAttribute(el.getAsJsonArray(), nested); + } catch (Exception e) { + } + + try { + return toAttribute(el.getAsJsonPrimitive(), nested); + } catch (Exception e) { + } + + log.warn("Unhandled extras element:" + el); + return null; + } + + protected Object toAttribute( JsonObject jo, boolean nested ) { + Map result = new HashMap<>(); + for( Map.Entry el : jo.entrySet() ) { + result.put(el.getKey(), toAttribute(el.getValue(), true)); + } + return result; + } + + protected Object toAttribute( JsonArray ja, boolean nested ) { + List result = new ArrayList<>(); + for( JsonElement el : ja ) { + result.add(toAttribute(el, true)); + } + return result; + } + + protected Object toAttribute( JsonPrimitive jp, boolean nested ) { + if( jp.isBoolean() ) { + return jp.getAsBoolean(); + } else if( jp.isNumber() ) { + // JME doesn't save Maps properly and treats them as two + // separate Lists... and it doesn't like saving Doubles + // in lists so we'll just return strings in the case where + // the value would end up in a map. If users someday really + // need properly typed map values and JME map storage hasn't + // been fixed then perhaps we give the users the option of + // flattening the nested properties into dot notation, ie: + // all directly on UserData with no Map children. + if( nested ) { + return jp.getAsString(); + } + Number num = jp.getAsNumber(); + // JME doesn't like to save GSON's LazilyParsedNumber so we'll + // convert it into a real number. I don't think we can reliably + // guess what type of number the user intended. It would take + // some expirimentation to determine if things like 0.0 are preserved + // during export or just get exported as 0. + // Rather than randomly flip-flop between number types depending + // on the inclusion (or not) of a decimal point, we'll just always + // return Double. + return num.doubleValue(); + } else if( jp.isString() ) { + return jp.getAsString(); + } + log.warn("Unhandled primitive:" + jp); + return null; + } +} diff --git a/jme3-blender/src/com/jme3/gde/blender/OutputReader.java b/jme3-blender/src/com/jme3/gde/blender/OutputReader.java new file mode 100644 index 000000000..10a942a2c --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/OutputReader.java @@ -0,0 +1,61 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.blender; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.api.progress.ProgressHandle; + +/** + * + * @author normenhansen + */ +public class OutputReader implements Runnable { + + private static final Logger logger = Logger.getLogger(OutputReader.class.getName()); + private Thread thread; + private BufferedReader in; + private ProgressHandle progress; + + public OutputReader(InputStream in) { + this.in = new BufferedReader(new InputStreamReader(in)); + } + + public OutputReader(BufferedReader in) { + this.in = in; + } + + public void start() { + thread = new Thread(this); + thread.start(); + } + + public void run() { + try { + String line; + while ((line = in.readLine()) != null) { + if (line.trim().length() > 0) { + if (progress != null) { + progress.progress(line); + } else { + logger.log(Level.INFO, "{0}", line); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * @param progress the progress to set + */ + public void setProgress(ProgressHandle progress) { + this.progress = progress; + } +} diff --git a/jme3-blender/src/com/jme3/gde/blender/glTF.svg b/jme3-blender/src/com/jme3/gde/blender/glTF.svg new file mode 100644 index 000000000..76318d73c --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/glTF.svg @@ -0,0 +1,22 @@ + +glTF logoAn open file format for three-dimensional scenes and models by Khronos Groupimage/svg+xml + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jme3-blender/src/com/jme3/gde/blender/scripts/Scripts.java b/jme3-blender/src/com/jme3/gde/blender/scripts/Scripts.java new file mode 100644 index 000000000..402089c8e --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/scripts/Scripts.java @@ -0,0 +1,66 @@ +/* + * 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.URI; +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"); + checkScript(folder, "import_fbx.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 = URI.create("nbres:" + root + name).toURL(); + 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); + } + } + } +} diff --git a/jme3-blender/src/com/jme3/gde/blender/scripts/import_3ds.py b/jme3-blender/src/com/jme3/gde/blender/scripts/import_3ds.py new file mode 100644 index 000000000..a61e10dd6 --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/scripts/import_3ds.py @@ -0,0 +1,83 @@ +# This script invokes blender to import and save external model formats as +# .blend files to be processed further. +# +# Example usage for this importer: +# blender --background --factory-startup --python $HOME/import_3ds.py -- \ +# --i="/tmp/hello.3ds" \ +# --o="/tmp/hello.blend" \ +# +# See blender --help for details. + +import bpy + +# Imports a file using importer +def import_file(file_path): + # Import the model + bpy.ops.import_scene.autodesk_3ds(filepath = file_path) + +# Clear existing objects. +def clear_scene(): + scene = bpy.context.scene + scene.camera = None + for obj in scene.objects: + scene.objects.unlink(obj) + +# Save current scene as .blend file +def save_file(save_path): + # Check if output file exists already + try: + f = open(save_path, 'w') + f.close() + ok = True + except: + print("Cannot save to path %r" % save_path) + + import traceback + traceback.print_exc() + + # Save .blend file + 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 + + # Run the conversion + clear_scene() + import_file(args.file_path) + save_file(args.save_path) + + print("batch job finished, exiting") + + +if __name__ == "__main__": + main() diff --git a/jme3-blender/src/com/jme3/gde/blender/scripts/import_dae.py b/jme3-blender/src/com/jme3/gde/blender/scripts/import_dae.py new file mode 100644 index 000000000..e996bf0e1 --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/scripts/import_dae.py @@ -0,0 +1,89 @@ +# This script invokes blender to import and save external model formats as +# .blend files to be processed further. +# +# Example usage for this importer: +# blender --background --factory-startup --python $HOME/import_3ds.py -- \ +# --i="/tmp/hello.3ds" \ +# --o="/tmp/hello.blend" \ +# +# See blender --help for details. + +import bpy + +# Imports a file using importer +def import_file(file_path): + # Import the model + bpy.ops.wm.collada_import(filepath = file_path) + +# Clear existing objects. +def clear_scene(): + scene = bpy.context.scene + scene.camera = None + for obj in scene.objects: + scene.objects.unlink(obj) + +# Save current scene as .blend file +def save_file(save_path): + # Check if output file exists already + try: + f = open(save_path, 'w') + f.close() + ok = True + except: + print("Cannot save to path %r" % save_path) + + import traceback + traceback.print_exc() + + # Save .blend file + if ok: + bpy.ops.wm.save_as_mainfile(filepath=save_path) + +# Due to an issue in the DAE importer, the file has to be resaved after an import +def open_save_file(save_path): + bpy.ops.wm.open_mainfile(filepath=save_path) + 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 + + # Run the conversion + clear_scene() + import_file(args.file_path) + save_file(args.save_path) + open_save_file(args.save_path) + + print("batch job finished, exiting") + + +if __name__ == "__main__": + main() diff --git a/jme3-blender/src/com/jme3/gde/blender/scripts/import_fbx.py b/jme3-blender/src/com/jme3/gde/blender/scripts/import_fbx.py new file mode 100644 index 000000000..296932d5f --- /dev/null +++ b/jme3-blender/src/com/jme3/gde/blender/scripts/import_fbx.py @@ -0,0 +1,83 @@ +# This script invokes blender to import and save external model formats as +# .blend files to be processed further. +# +# Example usage for this importer: +# blender --background --factory-startup --python $HOME/import_3ds.py -- \ +# --i="/tmp/hello.3ds" \ +# --o="/tmp/hello.blend" \ +# +# See blender --help for details. + +import bpy + +# Imports a file using importer +def import_file(file_path): + # Import the model + bpy.ops.import_scene.fbx(filepath = file_path) + +# Clear existing objects. +def clear_scene(): + scene = bpy.context.scene + scene.camera = None + for obj in scene.objects: + scene.objects.unlink(obj) + +# Save current scene as .blend file +def save_file(save_path): + # Check if output file exists already + try: + f = open(save_path, 'w') + f.close() + ok = True + except: + print("Cannot save to path %r" % save_path) + + import traceback + traceback.print_exc() + + # Save .blend file + 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 + + # Run the conversion + clear_scene() + import_file(args.file_path) + save_file(args.save_path) + + print("batch job finished, exiting") + + +if __name__ == "__main__": + main() diff --git a/nbproject/project.properties b/nbproject/project.properties index c14f032fd..b4a38c9b9 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,4 +1,4 @@ -#Sat, 06 Jun 2026 10:35:30 +0200 +#Sat, 06 Jun 2026 10:35:30 app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif #same as ${branding.token} app.name=jmonkeyplatform @@ -7,7 +7,7 @@ app.description=A complete 3D game development suite written purely in Java. app.categories=Development,Graphics,IDE,3DGraphics,Java app.icon.icns=jmonkeyplatform.icns #version name used for application and settings folder, no spaces! -app.version=3.8.1-SNAPSHOT +app.version=3.8.1 #version number used for plugins, only 3 numbers (e.g. 3.1.3) plugins.version=3.8.1 nbm.revision=2743 @@ -45,6 +45,7 @@ modules=\ ${project.com.jme3.gde.welcome}:\ ${project.com.jme3.gde.codecheck}:\ ${project.com.jme3.gde.obfuscate}:\ + ${project.com.jme3.gde.blender}:\ ${project.com.jme3.gde.angelfont}:\ ${project.com.jme3.gde.android}:\ ${project.com.jme3.gde.nmgen}:\ @@ -56,6 +57,7 @@ modules=\ project.com.jme3.gde.android=jme3-android project.com.jme3.gde.angelfont=jme3-angelfont project.com.jme3.gde.assetbrowser=jme3-assetbrowser +project.com.jme3.gde.blender=jme3-blender project.com.jme3.gde.codecheck=jme3-code-check project.com.jme3.gde.customcontrols=jme3-custom-controls project.com.jme3.gde.desktop.executables=jme3-desktop-executables