Add MTL & texture classes

This commit is contained in:
SiboVG 2023-08-15 03:49:39 +02:00
parent bff72d3532
commit 5a5b58e8c2
8 changed files with 1440 additions and 59 deletions

View File

@ -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<values.length; i++)
{
for (int i = 0; i < values.length; i++) {
values[i] = f.get(i);
}
return values;
@ -136,7 +134,7 @@ public final class DefaultFloatTuple implements FloatTuple {
*
* @param x The component to set
* @throws IndexOutOfBoundsException If this tuple has less than 1
* dimensions
* dimensions
*/
public void setX(float x) {
values[0] = x;
@ -152,7 +150,7 @@ public final class DefaultFloatTuple implements FloatTuple {
*
* @param y The component to set
* @throws IndexOutOfBoundsException If this tuple has less than 2
* dimensions
* dimensions
*/
public void setY(float y) {
values[1] = y;
@ -168,7 +166,7 @@ public final class DefaultFloatTuple implements FloatTuple {
*
* @param z The component to set
* @throws IndexOutOfBoundsException If this tuple has less than 3
* dimensions
* dimensions
*/
public void setZ(float z) {
values[2] = z;
@ -184,7 +182,7 @@ public final class DefaultFloatTuple implements FloatTuple {
*
* @param w The component to set
* @throws IndexOutOfBoundsException If this tuple has less than 4
* dimensions
* dimensions
*/
void setW(float w) {
values[3] = w;
@ -200,9 +198,9 @@ public final class DefaultFloatTuple implements FloatTuple {
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int i=0; i<getDimensions(); i++) {
for (int i = 0; i < getDimensions(); i++) {
sb.append(get(i));
if (i < getDimensions()-1) {
if (i < getDimensions() - 1) {
sb.append(",");
}
}
@ -224,15 +222,15 @@ public final class DefaultFloatTuple implements FloatTuple {
return false;
}
if (object instanceof DefaultFloatTuple) {
DefaultFloatTuple other = (DefaultFloatTuple)object;
DefaultFloatTuple other = (DefaultFloatTuple) object;
return Arrays.equals(values, other.values);
}
if (object instanceof FloatTuple) {
FloatTuple other = (FloatTuple)object;
FloatTuple other = (FloatTuple) object;
if (other.getDimensions() != getDimensions()) {
return false;
}
for (int i=0; i<getDimensions(); i++) {
for (int i = 0; i < getDimensions(); i++) {
if (get(i) != other.get(i)) {
return false;
}

View File

@ -0,0 +1,759 @@
/*
* 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.Mtl;
import de.javagl.obj.TextureOptions;
import java.util.ArrayList;
import java.util.List;
/**
* Default implementation of an Mtl (material)
*/
final class DefaultMtl implements Mtl {
/**
* The name of this material
*/
private final String name;
/**
* The illumination mode
*/
private Integer illum;
/**
* The optical density
*/
private Float ni;
/**
* The transmission filter
*/
private FloatTuple tf;
/**
* The sharpness of reflections
*/
private Float sharpness;
/**
* The ambient part of this material
*/
private FloatTuple ka;
/**
* The ambient map texture options
*/
private TextureOptions mapKaOptions;
/**
* The diffuse part of this material
*/
private FloatTuple kd;
/**
* The diffuse map texture options
*/
private TextureOptions mapKdOptions;
/**
* The specular part of this material
*/
private FloatTuple ks;
/**
* The specular map texture options
*/
private TextureOptions mapKsOptions;
/**
* The shininess of this material
*/
private Float ns;
/**
* The shininess map texture options
*/
private TextureOptions mapNsOptions;
/**
* The opacity of this material
*/
private Float d;
/**
* The halo flag for the opacity
*/
private Boolean halo;
/**
* The opacity map texture options
*/
private TextureOptions mapDOptions;
/**
* The bump map texture options
*/
private TextureOptions bumpOptions;
/**
* The displacement map texture options
*/
private TextureOptions dispOptions;
/**
* The decal map texture options
*/
private TextureOptions decalOptions;
/**
* The reflection map texture options
*/
private final List<TextureOptions> 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<TextureOptions>();
}
@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<TextureOptions> 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();
}
}

View File

@ -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<? extends Mtl> 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<? extends Mtl> 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<TextureOptions> 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 <code>null</code>
*
* @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 <code>null</code>
*
* @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 <code>null</code>
*
* @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 <code>null</code>
*
* @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
}
}

View File

@ -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<indices.length; i++) {
for (int i = 0; i < indices.length; i++) {
if (indices[i] < 0) {
throw new IllegalArgumentException(
name+" index is negative: "+indices[i]);
name + " index is negative: " + indices[i]);
}
if (indices[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);
}
}
}

View File

@ -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) {

View File

@ -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() + "]";
}

View File

@ -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());
}
}

View File

@ -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.
* <b>NOTE: this uses the Wavefront OBJ coordinate system</b>
@ -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 <code>u</code> component is <code>null</code>, then
* <code>null</code> is returned. If the <code>v</code> or
* <code>w</code> 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 <code>r</code> component is <code>null</code>, then
* <code>null</code> is returned. If the <code>g</code> or
* <code>b</code> component is null, then the <code>r</code>
* 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);
}
}