From aade8c5f6a7dc475a448f5f9a6263d2fe9a8481e Mon Sep 17 00:00:00 2001 From: Tobias Knerr Date: Sun, 21 May 2023 12:37:20 +0200 Subject: [PATCH] Support string replacement on texture references This allows glTF models intended for web use to share textures. --- .../target/common/ResourceOutputSettings.java | 31 ++++++++++++++++--- .../core/target/gltf/GltfTarget.java | 9 ++++-- .../osm2world/core/target/obj/ObjTarget.java | 9 ++++-- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/osm2world/core/target/common/ResourceOutputSettings.java b/src/main/java/org/osm2world/core/target/common/ResourceOutputSettings.java index 33ae938f..8c76d910 100644 --- a/src/main/java/org/osm2world/core/target/common/ResourceOutputSettings.java +++ b/src/main/java/org/osm2world/core/target/common/ResourceOutputSettings.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; import java.net.URI; +import java.util.function.Function; import javax.annotation.Nullable; import javax.imageio.ImageIO; @@ -19,9 +20,20 @@ public record ResourceOutputSettings( ResourceOutputMode modeForStaticResources, ResourceOutputMode modeForGeneratedResources, - URI textureDirectory + URI textureDirectory, + Function textureReferenceMapping ) { + public String buildTextureReference(TextureData texture) { + + if (!(texture instanceof ImageFileTexture fileTexture)) { + throw new IllegalArgumentException("Cannot reference runtime-generated textures: " + texture); + } + + return textureReferenceMapping.apply(fileTexture.getFile().getAbsolutePath()); + + } + public enum ResourceOutputMode { /** store the resource inside the model file */ EMBED, @@ -63,7 +75,9 @@ public String storeTexture(TextureData texture, @Nullable URI baseForRelativePat } - public static ResourceOutputSettings fromConfig(Configuration config, URI defaultTextureDirectory, boolean canEmbed) { + public static ResourceOutputSettings fromConfig(Configuration config, URI textureDirectory, boolean canEmbed) { + + /* parse the modes */ ResourceOutputMode modeForStaticResources = canEmbed ? EMBED : REFERENCE; ResourceOutputMode modeForGeneratedResources = canEmbed ? EMBED : STORE_SEPARATELY_AND_REFERENCE; @@ -76,7 +90,16 @@ public static ResourceOutputSettings fromConfig(Configuration config, URI defaul modeForGeneratedResources = ResourceOutputMode.valueOf(config.getString("generatedResourceOutputMode", "")); } catch (IllegalArgumentException ignored) { /* keep existing value */ } - URI textureDirectory = defaultTextureDirectory; + /* parse the texture reference mapping */ + + Function textureReferenceMapping = Function.identity(); + + @Nullable String regex = config.getString("textureReferenceMappingFrom", null); + @Nullable String replacement = config.getString("textureReferenceMappingTo", null); + + if (regex != null && replacement != null) { + textureReferenceMapping = (String input) -> input.replaceAll(regex, replacement); + } /* perform some validation */ @@ -90,7 +113,7 @@ public static ResourceOutputSettings fromConfig(Configuration config, URI defaul /* build and return the result */ - return new ResourceOutputSettings(modeForStaticResources, modeForGeneratedResources, textureDirectory); + return new ResourceOutputSettings(modeForStaticResources, modeForGeneratedResources, textureDirectory, textureReferenceMapping); } diff --git a/src/main/java/org/osm2world/core/target/gltf/GltfTarget.java b/src/main/java/org/osm2world/core/target/gltf/GltfTarget.java index 6070b8a6..a717aabc 100644 --- a/src/main/java/org/osm2world/core/target/gltf/GltfTarget.java +++ b/src/main/java/org/osm2world/core/target/gltf/GltfTarget.java @@ -30,7 +30,10 @@ import org.osm2world.core.target.common.MeshTarget; import org.osm2world.core.target.common.MeshTarget.MergeMeshes.MergeOption; import org.osm2world.core.target.common.ResourceOutputSettings; -import org.osm2world.core.target.common.material.*; +import org.osm2world.core.target.common.material.Material; +import org.osm2world.core.target.common.material.Materials; +import org.osm2world.core.target.common.material.TextureData; +import org.osm2world.core.target.common.material.TextureLayer; import org.osm2world.core.target.common.mesh.LevelOfDetail; import org.osm2world.core.target.common.mesh.Mesh; import org.osm2world.core.target.common.mesh.TriangleGeometry; @@ -406,9 +409,9 @@ private int createTexture(TextureData textureData) throws IOException { ResourceOutputSettings.ResourceOutputMode mode = resourceOutputSettings.modeForTexture(textureData); String uri = switch (mode) { - case EMBED -> textureData.getDataUri(); - case REFERENCE -> ((ImageFileTexture)textureData).getFile().getAbsolutePath(); + case REFERENCE -> resourceOutputSettings.buildTextureReference(textureData); case STORE_SEPARATELY_AND_REFERENCE -> resourceOutputSettings.storeTexture(textureData, outputDir.toURI()); + case EMBED -> textureData.getDataUri(); }; int imageIndex = imageIndexMap.containsKey(uri) ? imageIndexMap.get(uri) : createImage(uri); diff --git a/src/main/java/org/osm2world/core/target/obj/ObjTarget.java b/src/main/java/org/osm2world/core/target/obj/ObjTarget.java index 161e9954..ca8f3eaf 100644 --- a/src/main/java/org/osm2world/core/target/obj/ObjTarget.java +++ b/src/main/java/org/osm2world/core/target/obj/ObjTarget.java @@ -18,9 +18,12 @@ import org.osm2world.core.math.VectorXZ; import org.osm2world.core.target.common.FaceTarget; import org.osm2world.core.target.common.ResourceOutputSettings; -import org.osm2world.core.target.common.material.*; +import org.osm2world.core.target.common.material.Material; import org.osm2world.core.target.common.material.Material.Transparency; +import org.osm2world.core.target.common.material.Materials; +import org.osm2world.core.target.common.material.TextureData; import org.osm2world.core.target.common.material.TextureData.Wrap; +import org.osm2world.core.target.common.material.TextureLayer; import org.osm2world.core.world.data.WorldObject; public class ObjTarget extends FaceTarget { @@ -212,9 +215,9 @@ private String textureToPath(TextureData texture) throws IOException { ResourceOutputSettings resourceOutputSettings = ResourceOutputSettings.fromConfig(config, textureDirectory.toURI(), false); String path = switch (resourceOutputSettings.modeForTexture(texture)) { - case REFERENCE -> ((ImageFileTexture)texture).getFile().getAbsolutePath(); + case REFERENCE -> resourceOutputSettings.buildTextureReference(texture); case STORE_SEPARATELY_AND_REFERENCE -> resourceOutputSettings.storeTexture(texture, objDirectory.toURI()); - default -> throw new UnsupportedOperationException("unsupported output mode"); + case EMBED -> throw new UnsupportedOperationException("unsupported output mode"); }; textureMap.put(texture, path);