diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultFloatTuple.java b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultFloatTuple.java index 18dc31b61..02d580a03 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultFloatTuple.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultFloatTuple.java @@ -58,7 +58,7 @@ public final class DefaultFloatTuple implements FloatTuple { * @param w The w value */ DefaultFloatTuple(float x, float y, float z, float w) { - this(new float[]{x,y,z,w}); + this(new float[]{x, y, z, w}); } /** @@ -69,7 +69,7 @@ public final class DefaultFloatTuple implements FloatTuple { * @param z The z value */ DefaultFloatTuple(float x, float y, float z) { - this(new float[]{x,y,z}); + this(new float[]{x, y, z}); } /** @@ -79,7 +79,7 @@ public final class DefaultFloatTuple implements FloatTuple { * @param y The y value */ DefaultFloatTuple(float x, float y) { - this(new float[]{x,y}); + this(new float[]{x, y}); } /** @@ -108,14 +108,12 @@ public final class DefaultFloatTuple implements FloatTuple { * @return The values */ private static float[] getValues(FloatTuple f) { - if (f instanceof DefaultFloatTuple) - { - DefaultFloatTuple other = (DefaultFloatTuple)f; + if (f instanceof DefaultFloatTuple) { + DefaultFloatTuple other = (DefaultFloatTuple) f; return other.values.clone(); } float values[] = new float[f.getDimensions()]; - for (int i=0; i reflOptions; + + // PBR Parameters: + + /** + * The roughness of this material + */ + private Float pr; + + /** + * The roughness map texture options + */ + private TextureOptions mapPrOptions; + + /** + * The metallic part of this material + */ + private Float pm; + + /** + * The metallic map texture options + */ + private TextureOptions mapPmOptions; + + /** + * The sheen part of this material + */ + private Float ps; + + /** + * The sheen map texture options + */ + private TextureOptions mapPsOptions; + + /** + * The clearcoat thickness of this material + */ + private Float pc; + + /** + * The clearcoat roughness of this material + */ + private Float pcr; + + /** + * The emissive part of this material + */ + private FloatTuple ke; + + /** + * The emissive map texture options + */ + private TextureOptions mapKeOptions; + + /** + * The anisotropy of this material + */ + private Float aniso; + + /** + * The anisotropy rotation of this material + */ + private Float anisor; + + /** + * The normal map texture options + */ + private TextureOptions normOptions; + + /** + * Creates a new material with the given name + * + * @param name The name of this material + */ + DefaultMtl(String name) { + this.name = name; + this.reflOptions = new ArrayList(); + } + + @Override + public String getName() { + return name; + } + + @Override + public Integer getIllum() { + return illum; + } + + @Override + public void setIllum(Integer illum) { + this.illum = illum; + } + + @Override + public Float getNi() { + return ni; + } + + @Override + public void setNi(Float ni) { + this.ni = ni; + } + + @Override + public FloatTuple getTf() { + return tf; + } + + @Override + public void setTf(Float r, Float g, Float b) { + this.tf = ObjUtils.createRgbTuple(r, g, b); + } + + @Override + public Float getSharpness() { + return sharpness; + } + + @Override + public void setSharpness(Float sharpness) { + this.sharpness = sharpness; + } + + + @Override + public FloatTuple getKa() { + return ka; + } + + @Override + public void setKa(Float r, Float g, Float b) { + this.ka = ObjUtils.createRgbTuple(r, g, b); + } + + @Override + public String getMapKa() { + if (mapKaOptions == null) { + return null; + } + return mapKaOptions.getFileName(); + } + + @Override + public void setMapKa(String mapKa) { + if (mapKaOptions == null) { + mapKaOptions = new DefaultTextureOptions(); + } + mapKaOptions.setFileName(mapKa); + } + + @Override + public TextureOptions getMapKaOptions() { + return mapKaOptions; + } + + @Override + public void setMapKaOptions(TextureOptions options) { + this.mapKaOptions = options; + } + + @Override + public FloatTuple getKd() { + return kd; + } + + @Override + public void setKd(Float r, Float g, Float b) { + this.kd = ObjUtils.createRgbTuple(r, g, b); + } + + @Override + public String getMapKd() { + if (mapKdOptions == null) { + return null; + } + return mapKdOptions.getFileName(); + } + + @Override + public void setMapKd(String mapKd) { + if (mapKdOptions == null) { + mapKdOptions = new DefaultTextureOptions(); + } + mapKdOptions.setFileName(mapKd); + } + + @Override + public TextureOptions getMapKdOptions() { + return mapKdOptions; + } + + @Override + public void setMapKdOptions(TextureOptions options) { + this.mapKdOptions = options; + } + + @Override + public FloatTuple getKs() { + return ks; + } + + @Override + public void setKs(Float r, Float g, Float b) { + this.ks = ObjUtils.createRgbTuple(r, g, b); + } + + @Override + public String getMapKs() { + if (mapKsOptions == null) { + return null; + } + return mapKsOptions.getFileName(); + } + + @Override + public void setMapKs(String mapKs) { + if (mapKsOptions == null) { + mapKsOptions = new DefaultTextureOptions(); + } + mapKsOptions.setFileName(mapKs); + } + + @Override + public TextureOptions getMapKsOptions() { + return mapKsOptions; + } + + @Override + public void setMapKsOptions(TextureOptions options) { + this.mapKsOptions = options; + } + + @Override + public Float getNs() { + return ns; + } + + @Override + public void setNs(Float ns) { + this.ns = ns; + } + + @Override + public String getMapNs() { + if (mapNsOptions == null) { + return null; + } + return mapNsOptions.getFileName(); + } + + @Override + public void setMapNs(String mapNs) { + if (mapNsOptions == null) { + mapNsOptions = new DefaultTextureOptions(); + } + mapNsOptions.setFileName(mapNs); + } + + @Override + public TextureOptions getMapNsOptions() { + return mapNsOptions; + } + + @Override + public void setMapNsOptions(TextureOptions options) { + this.mapNsOptions = options; + } + + @Override + public Float getD() { + return d; + } + + @Override + public void setD(Float d) { + this.d = d; + } + + @Override + public Boolean isHalo() { + return halo; + } + + @Override + public void setHalo(Boolean halo) { + this.halo = halo; + } + + @Override + public String getMapD() { + if (mapDOptions == null) { + return null; + } + return mapDOptions.getFileName(); + } + + @Override + public void setMapD(String mapD) { + if (mapDOptions == null) { + mapDOptions = new DefaultTextureOptions(); + } + mapDOptions.setFileName(mapD); + } + + @Override + public TextureOptions getMapDOptions() { + return mapDOptions; + } + + @Override + public void setMapDOptions(TextureOptions options) { + this.mapDOptions = options; + } + + @Override + public String getBump() { + if (bumpOptions == null) { + return null; + } + return bumpOptions.getFileName(); + } + + @Override + public void setBump(String bump) { + if (bumpOptions == null) { + bumpOptions = new DefaultTextureOptions(); + } + bumpOptions.setFileName(bump); + } + + @Override + public TextureOptions getBumpOptions() { + return bumpOptions; + } + + @Override + public void setBumpOptions(TextureOptions options) { + this.bumpOptions = options; + } + + @Override + public String getDisp() { + if (dispOptions == null) { + return null; + } + return dispOptions.getFileName(); + } + + @Override + public void setDisp(String disp) { + if (dispOptions == null) { + dispOptions = new DefaultTextureOptions(); + } + dispOptions.setFileName(disp); + } + + @Override + public TextureOptions getDispOptions() { + return dispOptions; + } + + @Override + public void setDispOptions(TextureOptions options) { + this.dispOptions = options; + } + + @Override + public String getDecal() { + if (decalOptions == null) { + return null; + } + return decalOptions.getFileName(); + } + + @Override + public void setDecal(String decal) { + if (decalOptions == null) { + decalOptions = new DefaultTextureOptions(); + } + decalOptions.setFileName(decal); + } + + @Override + public TextureOptions getDecalOptions() { + return decalOptions; + } + + @Override + public void setDecalOptions(TextureOptions options) { + this.decalOptions = options; + } + + @Override + public List getReflOptions() { + return reflOptions; + } + + // PRB parameters + + @Override + public Float getPr() { + return pr; + } + + @Override + public void setPr(Float pr) { + this.pr = pr; + } + + @Override + public String getMapPr() { + if (mapPrOptions == null) { + return null; + } + return mapPrOptions.getFileName(); + } + + @Override + public void setMapPr(String mapPr) { + if (mapPrOptions == null) { + mapPrOptions = new DefaultTextureOptions(); + } + mapPrOptions.setFileName(mapPr); + } + + @Override + public TextureOptions getMapPrOptions() { + return mapPrOptions; + } + + @Override + public void setMapPrOptions(TextureOptions options) { + this.mapPrOptions = options; + } + + @Override + public Float getPm() { + return pm; + } + + @Override + public void setPm(Float pm) { + this.pm = pm; + } + + @Override + public String getMapPm() { + if (mapPmOptions == null) { + return null; + } + return mapPmOptions.getFileName(); + } + + @Override + public void setMapPm(String mapPm) { + if (mapPmOptions == null) { + mapPmOptions = new DefaultTextureOptions(); + } + mapPmOptions.setFileName(mapPm); + } + + @Override + public TextureOptions getMapPmOptions() { + return mapPmOptions; + } + + @Override + public void setMapPmOptions(TextureOptions options) { + this.mapPmOptions = options; + } + + @Override + public Float getPs() { + return ps; + } + + @Override + public void setPs(Float ps) { + this.ps = ps; + } + + @Override + public String getMapPs() { + if (mapPsOptions == null) { + return null; + } + return mapPsOptions.getFileName(); + } + + @Override + public void setMapPs(String mapPs) { + if (mapPsOptions == null) { + mapPsOptions = new DefaultTextureOptions(); + } + mapPsOptions.setFileName(mapPs); + } + + @Override + public TextureOptions getMapPsOptions() { + return mapPsOptions; + } + + @Override + public void setMapPsOptions(TextureOptions options) { + this.mapPsOptions = options; + } + + @Override + public Float getPc() { + return pc; + } + + @Override + public void setPc(Float pc) { + this.pc = pc; + } + + @Override + public Float getPcr() { + return pcr; + } + + @Override + public void setPcr(Float pcr) { + this.pcr = pcr; + } + + @Override + public FloatTuple getKe() { + return ke; + } + + @Override + public void setKe(Float r, Float g, Float b) { + this.ke = ObjUtils.createRgbTuple(r, g, b); + } + + @Override + public String getMapKe() { + if (mapKeOptions == null) { + return null; + } + return mapKeOptions.getFileName(); + } + + @Override + public void setMapKe(String mapKe) { + if (mapKeOptions == null) { + mapKeOptions = new DefaultTextureOptions(); + } + mapKeOptions.setFileName(mapKe); + } + + @Override + public TextureOptions getMapKeOptions() { + return mapKeOptions; + } + + @Override + public void setMapKeOptions(TextureOptions options) { + this.mapKeOptions = options; + } + + @Override + public Float getAniso() { + return aniso; + } + + @Override + public void setAniso(Float aniso) { + this.aniso = aniso; + } + + @Override + public Float getAnisor() { + return anisor; + } + + @Override + public void setAnisor(Float anisor) { + this.anisor = anisor; + } + + @Override + public String getNorm() { + if (normOptions == null) { + return null; + } + return normOptions.getFileName(); + } + + @Override + public void setNorm(String norm) { + if (normOptions == null) { + normOptions = new DefaultTextureOptions(); + } + normOptions.setFileName(norm); + } + + @Override + public TextureOptions getNormOptions() { + return normOptions; + } + + @Override + public void setNormOptions(TextureOptions options) { + this.normOptions = options; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Mtl"); + sb.append("["); + sb.append("name=").append(getName()); + sb.append("]"); + return sb.toString(); + } + +} diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultMtlWriter.java b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultMtlWriter.java new file mode 100644 index 000000000..a11670060 --- /dev/null +++ b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultMtlWriter.java @@ -0,0 +1,258 @@ +/* + * www.javagl.de - Obj + * + * Copyright (c) 2008-2015 Marco Hutter - http://www.javagl.de + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.sf.openrocket.file.wavefrontobj; + +import de.javagl.obj.FloatTuple; +import de.javagl.obj.FloatTuples; +import de.javagl.obj.Mtl; +import de.javagl.obj.TextureOptions; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.List; + +/** + * A class that may write {@link Mtl} objects into an MTL file + */ +public class DefaultMtlWriter { + /** + * Write the given {@link Mtl} objects to the given stream. The caller + * is responsible for closing the stream. + * + * @param mtls The {@link Mtl} objects + * @param outputStream The stream to write to + * @throws IOException If an IO error occurs + */ + public static void write( + Iterable mtls, OutputStream outputStream) + throws IOException { + OutputStreamWriter outputStreamWriter = + new OutputStreamWriter(outputStream); + write(mtls, outputStreamWriter); + } + + /** + * Write the given {@link Mtl} objects to the given writer. The caller + * is responsible for closing the writer. + * + * @param mtls The {@link Mtl} objects + * @param writer The writer to write to + * @throws IOException If an IO error occurs + */ + public static void write( + Iterable mtls, Writer writer) + throws IOException { + for (Mtl mtl : mtls) { + write(mtl, writer); + } + } + + /** + * Write the given {@link Mtl} to the given writer + * + * @param mtl The {@link Mtl} + * @param writer The writer + * @throws IOException If an IO error occurs + */ + private static void write(Mtl mtl, Writer writer) + throws IOException { + writer.write(createString(mtl)); + writer.flush(); + } + + /** + * Create the string representation of the given {@link Mtl}, as it + * is written into an MTL file + * + * @param mtl The {@link Mtl} + * @return The string representation + */ + public static String createString(Mtl mtl) { + StringBuilder sb = new StringBuilder("newmtl "); + sb.append(mtl.getName()).append("\n"); + + append(sb, "illum", mtl.getIllum(), "\n"); + append(sb, "Ns", mtl.getNs(), "\n"); + append(sb, "Ni", mtl.getNi(), "\n"); + + Float opacity = mtl.getD(); + if (opacity != null) { + sb.append("d").append(" "); + if (Boolean.TRUE.equals(mtl.isHalo())) { + sb.append("-halo").append(" "); + } + sb.append(opacity); + sb.append("\n"); + } + + appendTuple(sb, "Ka", mtl.getKa(), "\n"); + appendTuple(sb, "Kd", mtl.getKd(), "\n"); + appendTuple(sb, "Ks", mtl.getKs(), "\n"); + appendTuple(sb, "Tf", mtl.getTf(), "\n"); + append(sb, "sharpness", mtl.getSharpness(), "\n"); + appendTextureOptions(sb, "map_Ka", mtl.getMapKaOptions()); + appendTextureOptions(sb, "map_Kd", mtl.getMapKdOptions()); + appendTextureOptions(sb, "map_Ks", mtl.getMapKsOptions()); + appendTextureOptions(sb, "map_Ns", mtl.getMapNsOptions()); + appendTextureOptions(sb, "map_d", mtl.getMapDOptions()); + appendTextureOptions(sb, "bump", mtl.getBumpOptions()); + appendTextureOptions(sb, "disp", mtl.getDispOptions()); + appendTextureOptions(sb, "decal", mtl.getDecalOptions()); + List refls = mtl.getReflOptions(); + for (TextureOptions refl : refls) { + appendTextureOptions(sb, "refl", refl); + } + + // PBR parameters + append(sb, "Pr", mtl.getPr(), "\n"); + appendTextureOptions(sb, "map_Pr", mtl.getMapPrOptions()); + append(sb, "Pm", mtl.getPm(), "\n"); + appendTextureOptions(sb, "map_Pm", mtl.getMapPmOptions()); + append(sb, "Ps", mtl.getPs(), "\n"); + appendTextureOptions(sb, "map_Ps", mtl.getMapPsOptions()); + append(sb, "Pc", mtl.getPc(), "\n"); + append(sb, "Pcr", mtl.getPcr(), "\n"); + appendTuple(sb, "Ke", mtl.getKe(), "\n"); + appendTextureOptions(sb, "map_Ke", mtl.getMapKeOptions()); + append(sb, "aniso", mtl.getAniso(), "\n"); + append(sb, "anisor", mtl.getAnisor(), "\n"); + appendTextureOptions(sb, "norm", mtl.getNormOptions()); + + return sb.toString(); + } + + /** + * Append the given {@link TextureOptions} to the given string builder, + * if they are not null + * + * @param sb The string builder + * @param key The key + * @param options The {@link TextureOptions} + */ + private static void appendTextureOptions( + StringBuilder sb, String key, TextureOptions options) { + if (options != null) { + sb.append(key).append(" "); + sb.append(createString(options)).append("\n"); + } + } + + /** + * Create the string representation for the given {@link TextureOptions}, + * as a single line that may be written to the MTL file + * + * @param options The {@link TextureOptions} + * @return The string representation + */ + static String createString(TextureOptions options) { + StringBuilder sb = new StringBuilder(); + append(sb, "-blendu", options.isBlendu(), " "); + append(sb, "-blendv", options.isBlendv(), " "); + append(sb, "-boost", options.getBoost(), " "); + appendTuple(sb, "-mm", options.getMm(), " "); + appendTuple(sb, "-o", options.getO(), " "); + appendTuple(sb, "-s", options.getS(), " "); + appendTuple(sb, "-t", options.getT(), " "); + append(sb, "-texres", options.getTexres(), " "); + append(sb, "-clamp", options.isClamp(), " "); + append(sb, "-bm", options.getBm(), " "); + append(sb, "-imfchan", options.getImfchan(), " "); + append(sb, "-type", options.getType(), " "); + sb.append(options.getFileName()); + return sb.toString(); + } + + /** + * Append the given key-value mapping to the given string builder, if + * the given value is not null + * + * @param sb The string builder + * @param key The key + * @param value The value + * @param separator The separator to append after the value + */ + private static void append( + StringBuilder sb, String key, Object value, String separator) { + if (value != null) { + sb.append(key).append(" "); + sb.append(value); + sb.append(separator); + } + } + + /** + * Append the given key-value mapping to the given string builder, if + * the given value is not null + * + * @param sb The string builder + * @param key The key + * @param value The value + * @param separator The separator to append after the value + */ + private static void append( + StringBuilder sb, String key, Boolean value, String separator) { + if (value != null) { + sb.append(key).append(" "); + if (value) { + sb.append("on"); + } else { + sb.append("off"); + } + sb.append(separator); + } + } + + /** + * Append the given key-value mapping to the given string builder, if + * the given value is not null + * + * @param sb The string builder + * @param key The key + * @param value The value + * @param separator The separator to append after the value + */ + private static void appendTuple( + StringBuilder sb, String key, FloatTuple value, String separator) { + if (value != null) { + sb.append(key).append(" "); + sb.append(FloatTuples.createString(value)); + sb.append(separator); + } + } + + /** + * Private constructor to prevent instantiation + */ + private DefaultMtlWriter() { + // Private constructor to prevent instantiation + } + + +} diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObj.java b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObj.java index bcf1b429a..6a86608ab 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObj.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObj.java @@ -178,6 +178,7 @@ public final class DefaultObj implements Obj { /** * Return a list of vertices from a list of vertex indices. + * * @param indices List of vertex indices * @return List of vertices */ @@ -252,6 +253,7 @@ public final class DefaultObj implements Obj { /** * Returns the {@link DefaultObjGroup} with the given name. If no such group exists in this object, * create a new one, add it to this object, and return it. + * * @param groupName The group name * @return The {@link DefaultObjGroup} */ @@ -293,7 +295,8 @@ public final class DefaultObj implements Obj { /** * Adds a vertex to this object. You can specify whether the added vertex should affect the objects bounds. - * @param vertex The vertex to add + * + * @param vertex The vertex to add * @param updateBounds Whether the added vertex should affect the objects bounds */ public void addVertex(FloatTuple vertex, boolean updateBounds) { @@ -311,9 +314,10 @@ public final class DefaultObj implements Obj { /** * Adds a vertex to this object. You can specify whether the added vertex should affect the objects bounds. - * @param x The x coordinate of the vertex - * @param y The y coordinate of the vertex - * @param z The z coordinate of the vertex + * + * @param x The x coordinate of the vertex + * @param y The y coordinate of the vertex + * @param z The z coordinate of the vertex * @param updateBounds Whether the added vertex should affect the objects bounds */ public void addVertex(float x, float y, float z, boolean updateBounds) { @@ -357,6 +361,7 @@ public final class DefaultObj implements Obj { /** * Adds a normal to this object. The normal will be normalized. + * * @param normal The normal */ @Override @@ -373,7 +378,8 @@ public final class DefaultObj implements Obj { /** * Sets the normal at the given index. The normal will be normalized. - * @param index The index to set the normal at + * + * @param index The index to set the normal at * @param normal The normal to set */ public void setNormal(int index, FloatTuple normal) { @@ -442,7 +448,7 @@ public final class DefaultObj implements Obj { @Override - public void addFace(int ... v) { + public void addFace(int... v) { addFace(v, null, null); } @@ -482,7 +488,7 @@ public final class DefaultObj implements Obj { @Override public String toString() { return "Obj[" + - "#vertices="+ vertices.size() + "," + + "#vertices=" + vertices.size() + "," + "#texCoords=" + texCoords.size() + "," + "#normals=" + normals.size() + "," + "#faces=" + faces.size() + "," + @@ -538,6 +544,7 @@ public final class DefaultObj implements Obj { /** * Returns the bounds (min and max vertex values) of the vertices of this Obj. + * * @return The bounds of this object */ public FloatTupleBounds getVertexBounds() { @@ -570,23 +577,23 @@ public final class DefaultObj implements Obj { * the given maximum. * * @param indices The indices - * @param max The maximum index, exclusive - * @param name The name of the index set + * @param max The maximum index, exclusive + * @param name The name of the index set * @throws IllegalArgumentException If the given indices are not valid */ private static void checkIndices(int[] indices, int max, String name) { if (indices == null) { return; } - for (int i=0; i= max) { throw new IllegalArgumentException( - name+" index is "+indices[i]+ - ", but must be smaller than "+max); + name + " index is " + indices[i] + + ", but must be smaller than " + max); } } } diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjFace.java b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjFace.java index 01c78d8b0..09773de1c 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjFace.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjFace.java @@ -53,9 +53,9 @@ public final class DefaultObjFace implements ObjFace { * Creates a face from the given parameters. References to the * given objects will be stored. * - * @param vertexIndices The vertex indices + * @param vertexIndices The vertex indices * @param texCoordIndices The texture coordinate indices - * @param normalIndices The normal indices + * @param normalIndices The normal indices */ public DefaultObjFace(int[] vertexIndices, int[] texCoordIndices, int[] normalIndices) { this.vertexIndices = vertexIndices; @@ -92,7 +92,7 @@ public final class DefaultObjFace implements ObjFace { /** * Set the specified index to the given value * - * @param n The index to set + * @param n The index to set * @param index The value of the index */ public void setVertexIndex(int n, int index) { @@ -102,7 +102,7 @@ public final class DefaultObjFace implements ObjFace { /** * Set the specified index to the given value * - * @param n The index to set + * @param n The index to set * @param index The value of the index */ public void setNormalIndex(int n, int index) { @@ -112,7 +112,7 @@ public final class DefaultObjFace implements ObjFace { /** * Set the specified index to the given value * - * @param n The index to set + * @param n The index to set * @param index The value of the index */ public void setTexCoordIndex(int n, int index) { @@ -127,9 +127,9 @@ public final class DefaultObjFace implements ObjFace { @Override public String toString() { StringBuilder result = new StringBuilder("ObjFace["); - for(int i = 0; i < getNumVertices(); i++) { + for (int i = 0; i < getNumVertices(); i++) { result.append(vertexIndices[i]); - if( texCoordIndices != null || normalIndices != null) { + if (texCoordIndices != null || normalIndices != null) { result.append("/"); } if (texCoordIndices != null) { diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjGroup.java b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjGroup.java index 9239fc352..8e9236687 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjGroup.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultObjGroup.java @@ -67,8 +67,7 @@ public final class DefaultObjGroup implements ObjGroup { * * @param face The face to add */ - public void addFace(ObjFace face) - { + public void addFace(ObjFace face) { faces.add(face); } @@ -77,20 +76,17 @@ public final class DefaultObjGroup implements ObjGroup { } @Override - public int getNumFaces() - { + public int getNumFaces() { return faces.size(); } @Override - public ObjFace getFace(int index) - { + public ObjFace getFace(int index) { return faces.get(index); } @Override - public String toString() - { + public String toString() { return "ObjGroup[name=" + name + ",#faces=" + faces.size() + "]"; } diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/DefaultTextureOptions.java b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultTextureOptions.java new file mode 100644 index 000000000..2d364adf7 --- /dev/null +++ b/core/src/net/sf/openrocket/file/wavefrontobj/DefaultTextureOptions.java @@ -0,0 +1,309 @@ +/* + * www.javagl.de - Obj + * + * Copyright (c) 2008-2015 Marco Hutter - http://www.javagl.de + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.sf.openrocket.file.wavefrontobj; + +import de.javagl.obj.FloatTuple; +import de.javagl.obj.FloatTuples; +import de.javagl.obj.TextureOptions; + +import java.util.Objects; + +/** + * Default implementation of {@link TextureOptions} + */ +final class DefaultTextureOptions implements TextureOptions { + /** + * The file name + */ + private String fileName; + + /** + * The horizontal blending state + */ + private Boolean blendu; + + /** + * The vertical blending state + */ + private Boolean blendv; + + /** + * The color correction state + */ + private Boolean cc; + + /** + * The mip-map boost value + */ + private Float boost; + + /** + * The map modifiers + */ + private FloatTuple mm; + + /** + * The origin offset + */ + private FloatTuple o; + + /** + * The scale + */ + private FloatTuple s; + + /** + * The turbulence + */ + private FloatTuple t; + + /** + * The texture resolution + */ + private Float texres; + + /** + * The clamping state + */ + private Boolean clamp; + + /** + * The bump multiplier + */ + private Float bm; + + /** + * The IMF channel + */ + private String imfchan; + + /** + * The type + */ + private String type; + + /** + * Default constructor + */ + DefaultTextureOptions() { + // Default constructor + } + + @Override + public String getFileName() { + return fileName; + } + + @Override + public void setFileName(String fileName) { + this.fileName = fileName; + } + + @Override + public Boolean isBlendu() { + return blendu; + } + + @Override + public void setBlendu(Boolean blendu) { + this.blendu = blendu; + } + + @Override + public Boolean isBlendv() { + return blendv; + } + + @Override + public void setBlendv(Boolean blendv) { + this.blendv = blendv; + } + + @Override + public Float getBoost() { + return boost; + } + + @Override + public Boolean isCc() { + return cc; + } + + @Override + public void setCc(Boolean cc) { + this.cc = cc; + } + + @Override + public void setBoost(Float boost) { + this.boost = boost; + } + + @Override + public FloatTuple getMm() { + return mm; + } + + @Override + public void setMm(Float base, Float gain) { + if (base == null && gain == null) { + this.mm = null; + } + float baseValue = (base == null ? 0.0f : base); + float gainValue = (gain == null ? 1.0f : gain); + this.mm = FloatTuples.create(baseValue, gainValue); + } + + @Override + public FloatTuple getO() { + return o; + } + + @Override + public void setO(Float u, Float v, Float w) { + this.o = ObjUtils.createUvwTuple(u, v, w, 0.0f); + } + + @Override + public FloatTuple getS() { + return s; + } + + @Override + public void setS(Float u, Float v, Float w) { + this.s = ObjUtils.createUvwTuple(u, v, w, 1.0f); + } + + @Override + public FloatTuple getT() { + return t; + } + + @Override + public void setT(Float u, Float v, Float w) { + this.t = ObjUtils.createUvwTuple(u, v, w, 0.0f); + } + + @Override + public Float getTexres() { + return texres; + } + + @Override + public void setTexres(Float texres) { + this.texres = texres; + } + + @Override + public Boolean isClamp() { + return clamp; + } + + @Override + public void setClamp(Boolean clamp) { + this.clamp = clamp; + } + + @Override + public Float getBm() { + return bm; + } + + @Override + public void setBm(Float bm) { + this.bm = bm; + } + + @Override + public String getImfchan() { + return imfchan; + } + + @Override + public void setImfchan(String imfchan) { + this.imfchan = imfchan; + } + + @Override + public String getType() { + return type; + } + + @Override + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("TextureOptions"); + sb.append("["); + sb.append(DefaultMtlWriter.createString(this)); + sb.append("]"); + return sb.toString(); + } + + @Override + public int hashCode() { + return Objects.hash(blendu, blendv, cc, bm, boost, clamp, fileName, + imfchan, mm, o, s, t, texres, type); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null) { + return false; + } + if (!(object instanceof TextureOptions)) { + return false; + } + TextureOptions other = (TextureOptions) object; + + return + Objects.equals(isBlendu(), other.isBlendu()) && + Objects.equals(isBlendv(), other.isBlendv()) && + Objects.equals(isCc(), other.isCc()) && + Objects.equals(getBm(), other.getBm()) && + Objects.equals(getBoost(), other.getBoost()) && + Objects.equals(isClamp(), other.isClamp()) && + Objects.equals(getFileName(), other.getFileName()) && + Objects.equals(getImfchan(), other.getImfchan()) && + Objects.equals(getMm(), other.getMm()) && + Objects.equals(getO(), other.getO()) && + Objects.equals(getS(), other.getS()) && + Objects.equals(getT(), other.getT()) && + Objects.equals(getTexres(), other.getTexres()) && + Objects.equals(getType(), other.getType()); + } + + +} diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/ObjUtils.java b/core/src/net/sf/openrocket/file/wavefrontobj/ObjUtils.java index f44a797c7..af3f2a6d7 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/ObjUtils.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/ObjUtils.java @@ -1,6 +1,7 @@ package net.sf.openrocket.file.wavefrontobj; import de.javagl.obj.FloatTuple; +import de.javagl.obj.FloatTuples; import de.javagl.obj.Obj; import de.javagl.obj.ObjFace; import de.javagl.obj.ObjGroup; @@ -119,6 +120,19 @@ public class ObjUtils { } } + /** + * Translates the vertices in the obj file so that the component is at the specified translation. + * @param obj The obj file to translate + * @param startIdx The index of the first vertex to translate + * @param endIdx The index of the last vertex to translate (inclusive) + * @param translation The translation coordinates to translate the component with (in OpenRocket coordinate system) + */ + public static void translateVerticesFromComponentLocation(DefaultObj obj, CoordTransform transformer, + int startIdx, int endIdx, Coordinate translation) { + FloatTuple translatedLoc = transformer.convertLoc(translation); + ObjUtils.translateVertices(obj, startIdx, endIdx, translatedLoc.getX(), translatedLoc.getY(), translatedLoc.getZ()); + } + /** * Rotate the vertices of an object. * NOTE: this uses the Wavefront OBJ coordinate system @@ -389,20 +403,6 @@ public class ObjUtils { } } - - /** - * Translates the vertices in the obj file so that the component is at the specified translation. - * @param obj The obj file to translate - * @param startIdx The index of the first vertex to translate - * @param endIdx The index of the last vertex to translate (inclusive) - * @param translation The translation coordinates to translate the component with (in OpenRocket coordinate system) - */ - public static void translateVerticesFromComponentLocation(DefaultObj obj, CoordTransform transformer, - int startIdx, int endIdx, Coordinate translation) { - FloatTuple translatedLoc = transformer.convertLoc(translation); - ObjUtils.translateVertices(obj, startIdx, endIdx, translatedLoc.getX(), translatedLoc.getY(), translatedLoc.getZ()); - } - /** * Merge a list of objs into a single obj. * @param objs The objs to merge @@ -431,4 +431,58 @@ public class ObjUtils { return merged; } + + /** + * Creates a {@link FloatTuple} from the given UVW values, treating + * optional values as described in the MTL specification: If + * the u component is null, then + * null is returned. If the v or + * w component is null, then the given default value + * will be used. + * + * @param u The u-component + * @param v The v-component + * @param w The w-component + * @param defaultValue The default value for v and w + * @return The {@link FloatTuple} + */ + public static FloatTuple createUvwTuple( + Float u, Float v, Float w, float defaultValue) { + if (u == null) { + return null; + } + float fu = u; + float fv = (v == null ? defaultValue : v); + float fw = (w == null ? defaultValue : w); + return FloatTuples.create(fu, fv, fw); + } + + /** + * Creates a {@link FloatTuple} from the given RGB values, treating + * optional values as described in the MTL specification: If + * the r component is null, then + * null is returned. If the g or + * b component is null, then the r + * component will be used instead. + * + * @param r The r-component + * @param g The g-component + * @param b The b-component + * @return The {@link FloatTuple} + */ + public static FloatTuple createRgbTuple(Float r, Float g, Float b) { + if (r == null) { + return null; + } + float fr = r; + float fg = r; + float fb = r; + if (g != null) { + fg = g; + } + if (b != null) { + fb = b; + } + return FloatTuples.create(fr, fg, fb); + } }