diff --git a/jme3-plugins/build.gradle b/jme3-plugins/build.gradle
index dabbe62a0..b26434cdd 100644
--- a/jme3-plugins/build.gradle
+++ b/jme3-plugins/build.gradle
@@ -14,4 +14,5 @@ sourceSets {
dependencies {
compile project(':jme3-core')
+ testCompile project(':jme3-desktop')
}
diff --git a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MExporter.java b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MExporter.java
new file mode 100644
index 000000000..285489a05
--- /dev/null
+++ b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MExporter.java
@@ -0,0 +1,77 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.material.plugin.export.material;
+
+import com.jme3.export.JmeExporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.export.Savable;
+import com.jme3.material.Material;
+import com.jme3.material.MaterialDef;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+/**
+ * Saves a Material to a j3m file with proper formatting.
+ *
+ * usage is :
+ *
+ * J3MExporter exporter = new J3MExporter();
+ * exporter.save(material, myFile);
+ * //or
+ * exporter.save(material, myOutputStream);
+ *
+ *
+ * @author tsr
+ * @author nehon (documentation and safety check)
+ */
+public class J3MExporter implements JmeExporter {
+
+ private final J3MRootOutputCapsule rootCapsule;
+
+ /**
+ * Create a J3MExporter
+ */
+ public J3MExporter() {
+ rootCapsule = new J3MRootOutputCapsule(this);
+ }
+
+ @Override
+ public void save(Savable object, OutputStream f) throws IOException {
+
+ if (!(object instanceof Material)) {
+ throw new IllegalArgumentException("J3MExporter can only save com.jme3.material.Material class");
+ }
+
+ OutputStreamWriter out = new OutputStreamWriter(f);
+
+ rootCapsule.clear();
+ object.write(this);
+ rootCapsule.writeToStream(out);
+
+ out.flush();
+ }
+
+ @Override
+ public void save(Savable object, File f) throws IOException {
+ try (FileOutputStream fos = new FileOutputStream(f)) {
+ save(object, fos);
+ }
+ }
+
+ @Override
+ public OutputCapsule getCapsule(Savable object) {
+ if ((object instanceof Material) || (object instanceof MaterialDef)) {
+ return rootCapsule;
+ }
+
+ return rootCapsule.getCapsule(object);
+ }
+
+}
diff --git a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MOutputCapsule.java b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MOutputCapsule.java
new file mode 100644
index 000000000..7dd6a2a59
--- /dev/null
+++ b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MOutputCapsule.java
@@ -0,0 +1,383 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.material.plugin.export.material;
+
+import com.jme3.asset.TextureKey;
+import com.jme3.export.OutputCapsule;
+import com.jme3.export.Savable;
+import com.jme3.material.MatParam;
+import com.jme3.material.MatParamTexture;
+import com.jme3.math.*;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.IntMap;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author tsr
+ */
+public class J3MOutputCapsule implements OutputCapsule {
+
+ private final HashMap parameters;
+ protected final J3MExporter exporter;
+
+ public J3MOutputCapsule(J3MExporter exporter) {
+ this.exporter = exporter;
+ parameters = new HashMap<>();
+ }
+
+ public void writeToStream(OutputStreamWriter out) throws IOException {
+ for (String key : parameters.keySet()) {
+ out.write(" ");
+ writeParameter(out, key, parameters.get(key));
+ out.write("\n");
+ }
+ }
+
+ protected void writeParameter(OutputStreamWriter out, String name, String value) throws IOException {
+ out.write(name);
+ out.write(" : ");
+ out.write(value);
+ }
+
+ public void clear() {
+ parameters.clear();
+ }
+
+ protected void putParameter(String name, String value) {
+ parameters.put(name, value);
+ }
+
+ @Override
+ public void write(boolean value, String name, boolean defVal) throws IOException {
+ if (value == defVal) {
+ return;
+ }
+
+ putParameter(name, ((value) ? "On" : "Off"));
+ }
+
+ @Override
+ public void writeStringSavableMap(Map map, String name, Map defVal) throws IOException {
+ for (String key : map.keySet()) {
+ Savable value = map.get(key);
+ if (defVal == null || !defVal.containsKey(key) || !defVal.get(key).equals(value)) {
+ putParameter(key, format(value));
+ }
+ }
+ }
+
+ protected String format(Savable value) {
+ if (value instanceof MatParamTexture) {
+ return formatMatParamTexture((MatParamTexture) value);
+ }
+ if (value instanceof MatParam) {
+ return formatMatParam((MatParam) value);
+ }
+
+ throw new UnsupportedOperationException(value.getClass() + ": Not supported yet.");
+ }
+
+ private String formatMatParam(MatParam param){
+ VarType type = param.getVarType();
+ Object val = param.getValue();
+ switch (type) {
+ case Boolean:
+ case Float:
+ case Int:
+ return val.toString();
+ case Vector2:
+ Vector2f v2 = (Vector2f) val;
+ return v2.getX() + " " + v2.getY();
+ case Vector3:
+ Vector3f v3 = (Vector3f) val;
+ return v3.getX() + " " + v3.getY() + " " + v3.getZ();
+ case Vector4:
+ // can be either ColorRGBA, Vector4f or Quaternion
+ if (val instanceof Vector4f) {
+ Vector4f v4 = (Vector4f) val;
+ return v4.getX() + " " + v4.getY() + " "
+ + v4.getZ() + " " + v4.getW();
+ } else if (val instanceof ColorRGBA) {
+ ColorRGBA color = (ColorRGBA) val;
+ return color.getRed() + " " + color.getGreen() + " "
+ + color.getBlue() + " " + color.getAlpha();
+ } else if (val instanceof Quaternion) {
+ Quaternion quat = (Quaternion) val;
+ return quat.getX() + " " + quat.getY() + " "
+ + quat.getZ() + " " + quat.getW();
+ } else {
+ throw new UnsupportedOperationException("Unexpected Vector4 type: " + val);
+ }
+
+ default:
+ return null; // parameter type not supported in J3M
+ }
+ }
+
+ protected static String formatMatParamTexture(MatParamTexture param) {
+ StringBuilder ret = new StringBuilder();
+ Texture tex = (Texture) param.getValue();
+ TextureKey key;
+ if (tex != null) {
+ key = (TextureKey) tex.getKey();
+
+ if (key != null && key.isFlipY()) {
+ ret.append("Flip ");
+ }
+
+ ret.append(formatWrapMode(tex, Texture.WrapAxis.S));
+ ret.append(formatWrapMode(tex, Texture.WrapAxis.T));
+ ret.append(formatWrapMode(tex, Texture.WrapAxis.R));
+
+ //Min and Mag filter
+ Texture.MinFilter def = Texture.MinFilter.BilinearNoMipMaps;
+ if (tex.getImage().hasMipmaps() || (key != null && key.isGenerateMips())) {
+ def = Texture.MinFilter.Trilinear;
+ }
+ if (tex.getMinFilter() != def) {
+ ret.append("Min").append(tex.getMinFilter().name()).append(" ");
+ }
+
+ if (tex.getMagFilter() != Texture.MagFilter.Bilinear) {
+ ret.append("Mag").append(tex.getMagFilter().name()).append(" ");
+ }
+
+ ret.append("\"").append(key.getName()).append("\"");
+ }
+
+ return ret.toString();
+ }
+
+ protected static String formatWrapMode(Texture texVal, Texture.WrapAxis axis) {
+ WrapMode mode;
+ try {
+ mode = texVal.getWrap(axis);
+ } catch (IllegalArgumentException e) {
+ //this axis doesn't exist on the texture
+ return "";
+ }
+ if (mode != WrapMode.EdgeClamp) {
+ return "Wrap" + mode.name() + "_" + axis.name() + " ";
+ }
+ return "";
+ }
+
+ @Override
+ public void write(Enum value, String name, Enum defVal) throws IOException {
+ if (value == defVal) {
+ return;
+ }
+
+ putParameter(name, value.toString());
+ }
+
+ @Override
+ public void write(float value, String name, float defVal) throws IOException {
+ if (value == defVal) {
+ return;
+ }
+
+ putParameter(name, Float.toString(value));
+ }
+
+ @Override
+ public void write(float[] value, String name, float[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(float[][] value, String name, float[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(double value, String name, double defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(double[] value, String name, double[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(double[][] value, String name, double[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(long value, String name, long defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(long[] value, String name, long[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(long[][] value, String name, long[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(short value, String name, short defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(short[] value, String name, short[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(short[][] value, String name, short[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(boolean[] value, String name, boolean[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(boolean[][] value, String name, boolean[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(String value, String name, String defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(String[] value, String name, String[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(String[][] value, String name, String[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(BitSet value, String name, BitSet defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(Savable object, String name, Savable defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(Savable[] objects, String name, Savable[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(Savable[][] objects, String name, Savable[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void writeSavableArrayList(ArrayList array, String name, ArrayList defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void writeSavableArrayListArray(ArrayList[] array, String name, ArrayList[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void writeSavableArrayListArray2D(ArrayList[][] array, String name, ArrayList[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void writeFloatBufferArrayList(ArrayList array, String name, ArrayList defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void writeByteBufferArrayList(ArrayList array, String name, ArrayList defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void writeSavableMap(Map extends Savable, ? extends Savable> map, String name, Map extends Savable, ? extends Savable> defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void writeIntSavableMap(IntMap extends Savable> map, String name, IntMap extends Savable> defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(FloatBuffer value, String name, FloatBuffer defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(IntBuffer value, String name, IntBuffer defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(ByteBuffer value, String name, ByteBuffer defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(ShortBuffer value, String name, ShortBuffer defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(byte value, String name, byte defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(byte[] value, String name, byte[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(byte[][] value, String name, byte[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(int value, String name, int defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(int[] value, String name, int[] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void write(int[][] value, String name, int[][] defVal) throws IOException {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+}
diff --git a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRenderStateOutputCapsule.java b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRenderStateOutputCapsule.java
new file mode 100644
index 000000000..0e3d368d5
--- /dev/null
+++ b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRenderStateOutputCapsule.java
@@ -0,0 +1,81 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.material.plugin.export.material;
+
+import com.jme3.export.OutputCapsule;
+import com.jme3.export.Savable;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.HashMap;
+
+/**
+ *
+ * @author tsr
+ */
+public class J3MRenderStateOutputCapsule extends J3MOutputCapsule {
+ protected final static HashMap NAME_MAP;
+ protected String offsetUnit;
+
+ static {
+ NAME_MAP = new HashMap<>();
+ NAME_MAP.put( "wireframe", "Wireframe");
+ NAME_MAP.put( "cullMode", "FaceCull");
+ NAME_MAP.put( "depthWrite", "DepthWrite");
+ NAME_MAP.put( "depthTest", "DepthTest");
+ NAME_MAP.put( "blendMode", "Blend");
+ NAME_MAP.put( "alphaFallOff", "AlphaTestFalloff");
+ NAME_MAP.put( "offsetFactor", "PolyOffset");
+ NAME_MAP.put( "colorWrite", "ColorWrite");
+ NAME_MAP.put( "pointSprite", "PointSprite");
+ NAME_MAP.put( "depthFunc", "DepthFunc");
+ NAME_MAP.put( "alphaFunc", "AlphaFunc");
+ }
+ public J3MRenderStateOutputCapsule(J3MExporter exporter) {
+ super(exporter);
+ }
+
+ public OutputCapsule getCapsule(Savable object) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ offsetUnit = "";
+ }
+
+ @Override
+ public void writeToStream(OutputStreamWriter out) throws IOException {
+ out.write(" AdditionalRenderState {\n");
+ super.writeToStream(out);
+ out.write(" }\n");
+ }
+
+ @Override
+ protected void writeParameter(OutputStreamWriter out, String name, String value) throws IOException {
+ out.write(name);
+ out.write(" ");
+ out.write(value);
+
+ if( "PolyOffset".equals(name) ) {
+ out.write(" ");
+ out.write(offsetUnit);
+ }
+ }
+
+ @Override
+ protected void putParameter(String name, String value ) {
+ if( "offsetUnits".equals(name) ) {
+ offsetUnit = value;
+ return;
+ }
+
+ if( !NAME_MAP.containsKey(name) )
+ return;
+
+ super.putParameter(NAME_MAP.get(name), value);
+ }
+}
diff --git a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRootOutputCapsule.java b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRootOutputCapsule.java
new file mode 100644
index 000000000..06461d86a
--- /dev/null
+++ b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MRootOutputCapsule.java
@@ -0,0 +1,97 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.material.plugin.export.material;
+
+import com.jme3.export.OutputCapsule;
+import com.jme3.export.Savable;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.HashMap;
+
+/**
+ * @author tsr
+ */
+public class J3MRootOutputCapsule extends J3MOutputCapsule {
+
+ private final HashMap outCapsules;
+ private String name;
+ private String materialDefinition;
+ private Boolean isTransparent;
+
+ public J3MRootOutputCapsule(J3MExporter exporter) {
+ super(exporter);
+ outCapsules = new HashMap<>();
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ isTransparent = null;
+ name = "";
+ materialDefinition = "";
+ outCapsules.clear();
+
+ }
+
+ public OutputCapsule getCapsule(Savable object) {
+ if (!outCapsules.containsKey(object)) {
+ outCapsules.put(object, new J3MRenderStateOutputCapsule(exporter));
+ }
+
+ return outCapsules.get(object);
+ }
+
+ @Override
+ public void writeToStream(OutputStreamWriter out) throws IOException {
+ out.write("Material " + name + " : " + materialDefinition + " {\n\n");
+ if (isTransparent != null)
+ out.write(" Transparent " + ((isTransparent) ? "On" : "Off") + "\n\n");
+
+ out.write(" MaterialParameters {\n");
+ super.writeToStream(out);
+ out.write(" }\n\n");
+
+ for (J3MOutputCapsule c : outCapsules.values()) {
+ c.writeToStream(out);
+ }
+ out.write("}\n");
+ }
+
+ @Override
+ public void write(String value, String name, String defVal) throws IOException {
+ switch (name) {
+ case "material_def":
+ materialDefinition = value;
+ break;
+ case "name":
+ this.name = value;
+ break;
+ default:
+ throw new UnsupportedOperationException(name + " string material parameter not supported yet");
+ }
+ }
+
+ @Override
+ public void write(boolean value, String name, boolean defVal) throws IOException {
+ if( value == defVal)
+ return;
+
+ switch (name) {
+ case "is_transparent":
+ isTransparent = value;
+ break;
+ default:
+ throw new UnsupportedOperationException(name + " boolean material parameter not supported yet");
+ }
+ }
+
+ @Override
+ public void write(Savable object, String name, Savable defVal) throws IOException {
+ object.write(exporter);
+ }
+
+}
diff --git a/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java b/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java
new file mode 100644
index 000000000..f7c3b9d9f
--- /dev/null
+++ b/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009-2016 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.material.plugin;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.material.plugin.export.material.J3MExporter;
+import com.jme3.system.JmeSystem;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Scanner;
+
+public class TestMaterialWrite {
+
+ private AssetManager assetManager;
+ private Material mat;
+
+ @Before
+ public void init() {
+ assetManager = JmeSystem.newAssetManager(
+ TestMaterialWrite.class.getResource("/com/jme3/asset/Desktop.cfg"));
+
+ mat = assetManager.loadMaterial("/testMat.j3m");
+ }
+
+
+ @Test
+ public void testWriteMat() {
+ assertNotNull(mat);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+ J3MExporter exporter = new J3MExporter();
+ try {
+ exporter.save(mat, stream);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ String reference = convertStreamToString(TestMaterialWrite.class.getResourceAsStream("/testMat.j3m"));
+// System.err.println(reference);
+// System.err.println(stream.toString());
+
+ assertEquals(reference.replaceAll("\\s",""), stream.toString().replaceAll("\\s",""));
+ }
+
+ private String convertStreamToString(java.io.InputStream is) {
+ Scanner s = new Scanner(is).useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ }
+
+}
diff --git a/jme3-plugins/src/test/resources/testMat.j3m b/jme3-plugins/src/test/resources/testMat.j3m
new file mode 100644
index 000000000..bcb9b36d0
--- /dev/null
+++ b/jme3-plugins/src/test/resources/testMat.j3m
@@ -0,0 +1,15 @@
+Material test : Common/MatDefs/Light/Lighting.j3md {
+
+ MaterialParameters {
+ Diffuse : 1.0 1.0 1.0 1.0
+ UseMaterialColors : true
+ ParallaxHeight : 0.05
+ Ambient : 1.0 1.0 1.0 1.0
+ DiffuseMap : Flip WrapRepeat_S WrapRepeat_T MinNearestNoMipMaps MagNearest "Textures/ColoredTex/Monkey.png"
+ Specular : 0.01375 0.01375 0.01375 1.0
+ Shininess : 50.0
+ }
+
+ AdditionalRenderState {
+ }
+}
\ No newline at end of file