Skip to content

Commit

Permalink
(#10) Add .mtl support alongside .obj writing
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasstarsz committed Aug 29, 2021
1 parent 81245a1 commit e30d566
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 39 deletions.
6 changes: 4 additions & 2 deletions src/main/java/tech/fastj/resources/models/ModelUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ private ModelUtil() {
}

private static final Map<String, Function<List<String>, Polygon2D[]>> ModelParser = Map.of(
SupportedModelFormats.Psdf, PsdfUtil::parse
SupportedModelFormats.Psdf, PsdfUtil::parse,
SupportedModelFormats.Obj, ObjUtil::parse
);

private static final Map<String, BiConsumer<Path, Model2D>> ModelWriter = Map.of(
SupportedModelFormats.Psdf, PsdfUtil::write
SupportedModelFormats.Psdf, PsdfUtil::write,
SupportedModelFormats.Obj, ObjUtil::write
);

/**
Expand Down
224 changes: 224 additions & 0 deletions src/main/java/tech/fastj/resources/models/MtlUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package tech.fastj.resources.models;

import tech.fastj.engine.CrashMessages;
import tech.fastj.engine.FastJEngine;
import tech.fastj.math.Maths;
import tech.fastj.math.Pointf;
import tech.fastj.graphics.Boundary;
import tech.fastj.graphics.game.Model2D;
import tech.fastj.graphics.game.Polygon2D;

import tech.fastj.resources.files.FileUtil;
import tech.fastj.resources.images.ImageResource;
import tech.fastj.resources.images.ImageUtil;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MtlUtil {

private static final String LineSeparator = System.lineSeparator();

private MtlUtil() {
throw new java.lang.IllegalStateException();
}

public static void write(Path destinationPath, Model2D model) {
Path destinationPathWithoutSpaces = Path.of(destinationPath.toString().replace(' ', '_'));
StringBuilder fileContents = new StringBuilder();
writeTimestamp(fileContents);

for (int i = 0; i < model.getPolygons().length; i++) {
Polygon2D polygon2D = model.getPolygons()[i];
writeMaterial(fileContents, polygon2D, destinationPathWithoutSpaces, i + 1);
}

try {
Files.writeString(destinationPathWithoutSpaces, fileContents, StandardCharsets.US_ASCII);
} catch (IOException exception) {
throw new IllegalStateException(CrashMessages.theGameCrashed("a .mtl file writing error."), exception);
}
}

private static void writeMaterial(StringBuilder fileContents, Polygon2D polygon, Path destinationPath, int materialIndex) {
fileContents.append(ParsingKeys.NewMaterial)
.append(' ')
.append("Polygon2D_material_")
.append(materialIndex)
.append(LineSeparator);

Paint material = polygon.getFill();
if (material instanceof LinearGradientPaint || material instanceof RadialGradientPaint) {
writeGradientMaterial(fileContents, polygon, destinationPath, materialIndex);
} else if (material instanceof Color) {
writeColorMaterial(fileContents, (Color) material);
} else if (material instanceof TexturePaint) {
writeTextureMaterial(fileContents, (TexturePaint) material, destinationPath, materialIndex);
} else {
FastJEngine.error(
CrashMessages.UnimplementedMethodError.errorMessage,
new UnsupportedOperationException(
"Writing paints other than LinearGradientPaint, RadialGradientPaint, Color, or TexturePaint is not supported."
+ System.lineSeparator()
+ "Check the github to confirm you are on the latest version, as that version may have more implemented features."
)
);
}
}

private static void writeGradientMaterial(StringBuilder fileContents, Polygon2D polygon, Path destinationPath, int materialIndex) {
writeDefaultColorValues(fileContents);

int extensionIndex = destinationPath.toString().indexOf(FileUtil.getFileExtension(destinationPath));
Path texturePath = Path.of(destinationPath.toString().substring(0, extensionIndex - 1).replace(' ', '_') + "_gradient_" + materialIndex + ".png");

Pointf polygonSize = Pointf.subtract(polygon.getBound(Boundary.BottomRight), polygon.getBound(Boundary.TopLeft)).multiply(2f);
BufferedImage bufferedImage = ImageUtil.createBufferedImage((int) (polygonSize.x / 2) + 1, (int) (polygonSize.y / 2) + 1);

Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.setPaint(polygon.getFill());
graphics2D.translate(-bufferedImage.getWidth(), -bufferedImage.getHeight());
graphics2D.fillRect(0, 0, (int) polygonSize.x + 1, (int) polygonSize.y + 1);
graphics2D.dispose();

ImageUtil.writeBufferedImage(bufferedImage, texturePath);
fileContents.append(ParsingKeys.TextureImage)
.append(' ')
.append(texturePath)
.append(LineSeparator)
.append(LineSeparator);
}

private static void writeTextureMaterial(StringBuilder fileContents, TexturePaint material, Path destinationPath, int materialIndex) {
writeDefaultColorValues(fileContents);

Path texturePath;
try {
texturePath = FastJEngine.getResourceManager(ImageResource.class).tryFindPathOfResource(material.getImage()).toAbsolutePath();
if (texturePath.toString().contains("\\s+")) {
throw new IllegalStateException("The file path for a texture image in .mtl cannot contain whitespace.");
}
} catch (IllegalArgumentException exception) {
int extensionIndex = destinationPath.toString().indexOf(FileUtil.getFileExtension(destinationPath));
texturePath = Path.of(destinationPath.toString().substring(0, extensionIndex - 1) + "_image_" + materialIndex + ".png");
ImageUtil.writeBufferedImage(material.getImage(), texturePath);
}

fileContents.append(ParsingKeys.TextureImage)
.append(' ')
.append(texturePath)
.append(LineSeparator)
.append(LineSeparator);
}

private static void writeDefaultColorValues(StringBuilder fileContents) {
fileContents.append(ParsingKeys.AmbientColor)
.append(' ')
.append(String.format("%6f", 1f))
.append(' ')
.append(String.format("%6f", 1f))
.append(' ')
.append(String.format("%6f", 1f))
.append(LineSeparator);
fileContents.append(ParsingKeys.DiffuseColor)
.append(' ')
.append(String.format("%6f", 1f))
.append(' ')
.append(String.format("%6f", 1f))
.append(' ')
.append(String.format("%6f", 1f))
.append(LineSeparator);
writeSpecularValues(fileContents);
fileContents.append(ParsingKeys.Transparency)
.append(' ')
.append(String.format("%6f", 1f))
.append(LineSeparator);
fileContents.append(ParsingKeys.IlluminationMode)
.append(' ')
.append(1)
.append(LineSeparator);
}

private static void writeTimestamp(StringBuilder fileContents) {
fileContents.append("# Generated by the FastJ Game Engine https://github.com/fastjengine/FastJ")
.append(LineSeparator)
.append("# Timestamp: ")
.append(new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(new Date()))
.append(LineSeparator)
.append(LineSeparator);
}

private static void writeColorMaterial(StringBuilder fileContents, Color colorMaterial) {
fileContents.append(ParsingKeys.AmbientColor)
.append(' ')
.append(String.format("%6f", Maths.normalize(colorMaterial.getRed(), 0f, 255f)))
.append(' ')
.append(String.format("%6f", Maths.normalize(colorMaterial.getGreen(), 0f, 255f)))
.append(' ')
.append(String.format("%6f", Maths.normalize(colorMaterial.getBlue(), 0f, 255f)))
.append(LineSeparator);
fileContents.append(ParsingKeys.DiffuseColor)
.append(' ')
.append(String.format("%6f", Maths.normalize(colorMaterial.getRed(), 0f, 255f)))
.append(' ')
.append(String.format("%6f", Maths.normalize(colorMaterial.getGreen(), 0f, 255f)))
.append(' ')
.append(String.format("%6f", Maths.normalize(colorMaterial.getBlue(), 0f, 255f)))
.append(LineSeparator);

writeSpecularValues(fileContents);

fileContents.append(ParsingKeys.Transparency)
.append(' ')
.append(String.format("%6f", Maths.normalize(colorMaterial.getAlpha(), 0f, 255f)))
.append(LineSeparator);
fileContents.append(ParsingKeys.IlluminationMode)
.append(' ')
.append(1)
.append(LineSeparator)
.append(LineSeparator);
}

private static void writeSpecularValues(StringBuilder fileContents) {
fileContents.append(ParsingKeys.SpecularColor)
.append(' ')
.append(String.format("%6f", 0f))
.append(' ')
.append(String.format("%6f", 0f))
.append(' ')
.append(String.format("%6f", 0f))
.append(LineSeparator);
fileContents.append(ParsingKeys.SpecularExponent)
.append(' ')
.append(String.format("%6f", 1f))
.append(LineSeparator);
}

public static class ParsingKeys {
private ParsingKeys() {
throw new java.lang.IllegalStateException();
}

public static final String Empty = "";
public static final String NewMaterial = "newmtl";
public static final String AmbientColor = "Ka";
public static final String DiffuseColor = "Kd";
public static final String SpecularColor = "Ks";
public static final String SpecularExponent = "Ns";
public static final String Transparency = "d";
public static final String IlluminationMode = "illum";
public static final String TextureMap = "map_Ka";
public static final String TextureImage = "map_Kd";
}
}
Loading

0 comments on commit e30d566

Please sign in to comment.