diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/MtlExpoter.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/MtlExpoter.java new file mode 100644 index 000000000..01c839ed4 --- /dev/null +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/MtlExpoter.java @@ -0,0 +1,68 @@ +package net.sf.openrocket.file.wavefrontobj.export; + +import net.sf.openrocket.appearance.Appearance; +import net.sf.openrocket.appearance.defaults.DefaultAppearance; +import net.sf.openrocket.file.wavefrontobj.DefaultMtl; +import net.sf.openrocket.file.wavefrontobj.DefaultObj; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.util.Color; + +import java.util.List; + +/** + * Helper class for exporting a rocket component's appearance to an MTL file. + * + * @author Sibo Van Gool + */ +public class MtlExpoter { + private final DefaultObj obj; + private final RocketComponent component; + private final String materialName; + private List materials; + + /** + * Export the appearance of a rocket component + * NOTE: you still have to call {@link #doExport()} to actually export the appearance. + * @param obj The obj file that will use the material + * @param component The component to export the appearance of + * @param materialName The name of the material to generate + * @param materials The list of materials to add the new material(s) to + */ + public MtlExpoter(DefaultObj obj, RocketComponent component, String materialName, List materials) { + this.obj = obj; + this.component = component; + this.materialName = materialName; + this.materials = materials; + } + + /** + * Export the appearance of the component to the MTL file. Also sets the active material group in the OBJ file. + */ + public void doExport() { + // Set the active material group + obj.setActiveMaterialGroupName(materialName); + DefaultMtl material = new DefaultMtl(materialName); + + // Get the component appearance + Appearance appearance = component.getAppearance(); + if (appearance == null) { + appearance = DefaultAppearance.getDefaultAppearance(component); + } + + // Apply coloring + Color color = appearance.getPaint(); + final float r = color.getRed()/255f; + final float g = color.getGreen()/255f; + final float b = color.getBlue()/255f; + material.setKd(r, g, b); // Diffuse color + material.setKa(0f, 0f, 0f); // No emission + material.setKs(1f, 1f, 1f); // Use white specular highlights + material.setD(color.getAlpha()/255f); // Opacity + material.setNs((float) appearance.getShine() * 750); // Shine (max is 1000, but this too strong compared to OpenRocket's max) + material.setIllum(2); // Use Phong reflection (specular highlights etc.) + + // TODO: Apply texture + + materials.add(material); + } +} diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/OBJExporterFactory.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/OBJExporterFactory.java index b77eeb40d..db93b8233 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/export/OBJExporterFactory.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/OBJExporterFactory.java @@ -2,6 +2,8 @@ package net.sf.openrocket.file.wavefrontobj.export; import de.javagl.obj.ObjWriter; import net.sf.openrocket.file.wavefrontobj.CoordTransform; +import net.sf.openrocket.file.wavefrontobj.DefaultMtl; +import net.sf.openrocket.file.wavefrontobj.DefaultMtlWriter; import net.sf.openrocket.file.wavefrontobj.DefaultObj; import net.sf.openrocket.file.wavefrontobj.ObjUtils; import net.sf.openrocket.file.wavefrontobj.export.components.BodyTubeExporter; @@ -94,6 +96,8 @@ public class OBJExporterFactory { public void doExport() { DefaultObj obj = new DefaultObj(); Map objFileMap; + Map> materials = new HashMap<>(); + materials.put(obj, new ArrayList<>()); boolean exportAsSeparateFiles = this.options.isExportAsSeparateFiles(); if (exportAsSeparateFiles) { @@ -129,11 +133,13 @@ public class OBJExporterFactory { // If separate export, create a new OBJ for each component if (exportAsSeparateFiles) { obj = new DefaultObj(); + materials.put(obj, new ArrayList<>()); } // Component exporting String groupName = idx + "_" + component.getName(); - handleComponent(obj, this.configuration, this.options.getTransformer(), component, groupName, this.options.getLOD()); + handleComponent(obj, this.configuration, this.options.getTransformer(), component, groupName, + materials.get(obj), this.options.getLOD(), options); // If separate export, add this object to the map of objects to export if (exportAsSeparateFiles) { @@ -169,6 +175,18 @@ public class OBJExporterFactory { ObjUtils.scaleVertices(obj, options.getScaling()); } + // Export materials + if (options.isExportAppearance()) { + String mtlFilePath = FileUtils.removeExtension(filePath) + ".mtl"; + List mtls = materials.get(obj); + try (OutputStream mtlOutputStream = new FileOutputStream(mtlFilePath)) { + DefaultMtlWriter.write(mtls, mtlOutputStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + obj.setMtlFileNames(List.of(mtlFilePath)); + } + // Write the OBJ file writeObj(obj, filePath); } @@ -184,7 +202,8 @@ public class OBJExporterFactory { @SuppressWarnings("unchecked") // This is safe because of the structure we set up. private void handleComponent(DefaultObj obj, FlightConfiguration config, CoordTransform transformer, - T component, String groupName, ObjUtils.LevelOfDetail LOD) { + T component, String groupName, List materials, + ObjUtils.LevelOfDetail LOD, OBJExportOptions options) { ExporterFactory factory = null; Class currentClass = component.getClass(); @@ -198,6 +217,12 @@ public class OBJExporterFactory { throw new IllegalArgumentException("Unsupported component type: " + component.getClass().getName()); } + // Export material + if (options.isExportAppearance()) { + MtlExpoter mtlExpoter = new MtlExpoter(obj, component, "mat_" + groupName, materials); + mtlExpoter.doExport(); + } + // Export component final RocketComponentExporter exporter = factory.create(obj, config, transformer, component, groupName, LOD); exporter.addToObj(); diff --git a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java index 347cc5f94..d5d11b5d8 100644 --- a/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java +++ b/core/src/net/sf/openrocket/file/wavefrontobj/export/components/RingComponentExporter.java @@ -19,6 +19,8 @@ public class RingComponentExporter extends RocketComponentExporter