From 1f8bd3ea1a3ad4d072e747669d071c92fc3c6d38 Mon Sep 17 00:00:00 2001 From: Deepseasaltyfish Date: Fri, 3 Apr 2026 20:25:02 +0800 Subject: [PATCH] fix wrong logic for normal and specular texture in apply and add lod for them --- .../java/cam72cam/mod/model/obj/OBJModel.java | 122 +++++++++++++++--- 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/src/main/java/cam72cam/mod/model/obj/OBJModel.java b/src/main/java/cam72cam/mod/model/obj/OBJModel.java index e90f51f6c..2aa16cd62 100644 --- a/src/main/java/cam72cam/mod/model/obj/OBJModel.java +++ b/src/main/java/cam72cam/mod/model/obj/OBJModel.java @@ -30,8 +30,8 @@ public class OBJModel { public final int textureHeight; public final int defaultLodSize; public final Map> textures = new HashMap<>(); - public final Map normals = new HashMap<>(); - public final Map speculars = new HashMap<>(); + public final Map> normals = new HashMap<>(); + public final Map> speculars = new HashMap<>(); public final LinkedHashMap groups; //Order by vertex start/stop public final boolean isSmoothShading; @@ -112,7 +112,7 @@ public OBJModel(Identifier modelLoc, float darken, double scale, Collection k.getString("variant"))) { ModCore.debug("%s : tex %s", modelLoc, variant); - Map lodMap = new HashMap<>(); + Map baseTexLodMap = new HashMap<>(); int texSize = Math.max(textureWidth, textureHeight); Supplier texData = cache.getResource(variant + ".rgba", builder -> { @@ -128,7 +128,7 @@ public OBJModel(Identifier modelLoc, float darken, double scale, Collection lodData = cache.getResource(variant + String.format("_%s.rgba", lodValue), builder -> new GenericByteBuffer(toRGBA(scaleImage(builder.getTextures().get(variant).get(), lodValue))) ); - lodMap.put(lodValue, new OBJTextureSheet(size.getLeft(), size.getRight(), lodData, cacheSeconds)); + baseTexLodMap.put(lodValue, new OBJTextureSheet(size.getLeft(), size.getRight(), lodData, cacheSeconds)); } } - this.textures.put(variant, lodMap); + this.textures.put(variant, baseTexLodMap); if (hasNormals) { + Map normalTexLodMap = new HashMap<>(); try { - Supplier normData = cache.getResource(variant + ".norm", builder -> new GenericByteBuffer(toRGBA(builder.getNormals().get(variant).get()))); - this.normals.put(variant, new OBJTextureSheet(textureWidth, textureHeight, normData, cacheSeconds)); + Supplier normData = cache.getResource(variant + ".norm", builder -> { + BufferedImage img = builder.getNormals().get(variant).get(); + if (Config.DebugTextureSheets) { + try { + File cacheFile = ModCore.cacheFile(new Identifier(modelLoc.getDomain() + "debug", modelLoc.getPath() + "_" + variant + "_norm.png")); + ModCore.info("Writing debug normal to " + cacheFile); + ImageIO.write(img, "png", cacheFile); + } catch (IOException e) { + ModCore.catching(e); + } + } + return new GenericByteBuffer(toRGBA(img)); + }); + normalTexLodMap.put(texSize, new OBJTextureSheet(textureWidth, textureHeight, normData, cacheSeconds)); + + for (Integer lodValue : lodValues) { + if (lodValue < texSize) { + Pair size = scaleSize(textureWidth, textureHeight, lodValue); + Supplier lodNormData = cache.getResource(variant + "_" + lodValue + ".norm", + builder -> new GenericByteBuffer(toRGBA(scaleImage(builder.getNormals().get(variant).get(), lodValue)))); + normalTexLodMap.put(lodValue, new OBJTextureSheet(size.getLeft(), size.getRight(), lodNormData, cacheSeconds)); + } + } + this.normals.put(variant, normalTexLodMap); } catch (Exception ex) { ModCore.warn("Unable to load normal map for %s, %s", modelLoc, ex); } } if (hasSpeculars) { + Map specularTexLodMap = new HashMap<>(); try { - Supplier specData = cache.getResource(variant + ".spec", builder -> new GenericByteBuffer(toRGBA(builder.getSpeculars().get(variant).get()))); - this.speculars.put(variant, new OBJTextureSheet(textureWidth, textureHeight, specData, cacheSeconds)); + Supplier specData = cache.getResource(variant + ".spec", builder -> { + BufferedImage img = builder.getSpeculars().get(variant).get(); + if (Config.DebugTextureSheets) { + try { + File cacheFile = ModCore.cacheFile(new Identifier(modelLoc.getDomain() + "debug", modelLoc.getPath() + "_" + variant + "_spec.png")); + ModCore.info("Writing debug specular to " + cacheFile); + ImageIO.write(img, "png", cacheFile); + } catch (IOException e) { + ModCore.catching(e); + } + } + return new GenericByteBuffer(toRGBA(img)); + }); + specularTexLodMap.put(texSize, new OBJTextureSheet(textureWidth, textureHeight, specData, cacheSeconds)); + + for (Integer lodValue : lodValues) { + if (lodValue < texSize) { + Pair size = scaleSize(textureWidth, textureHeight, lodValue); + Supplier lodSpecData = cache.getResource(variant + "_" + lodValue + ".spec", + builder -> new GenericByteBuffer(toRGBA(scaleImage(builder.getSpeculars().get(variant).get(), lodValue)))); + specularTexLodMap.put(lodValue, new OBJTextureSheet(size.getLeft(), size.getRight(), lodSpecData, cacheSeconds)); + } + } + this.speculars.put(variant, specularTexLodMap); } catch (Exception ex) { ModCore.warn("Unable to load specular map for %s, %s", modelLoc, ex); } @@ -302,18 +348,62 @@ public void apply(RenderState state) { } } - - - if (lodSize == defaultLodSize && OBJModel.this.normals.containsKey(texName)) { - state.normals(OBJModel.this.normals.get(texName).synchronous(wait)); + OBJTextureSheet normTex = null; + if (OBJModel.this.normals.containsKey(texName)) { + Map normLodMap = OBJModel.this.normals.get(texName); + normTex = normLodMap.get(lodSize); + if (normTex == null) { + normTex = normLodMap.get(defaultLodSize); + } + } + if (normTex != null) { + if (wait) { + state.normals(normTex.synchronous(true)); + } else { + normTex.getId(); + if (!normTex.isLoaded()) { + normTex = OBJModel.this.normals.get(texName).values().stream() + .filter(CustomTexture::isLoaded) + .findAny().orElse(null); + } + if (normTex != null) { + state.normals(normTex); + } else { + state.normals(defTex); + } + } } else { state.normals(defTex); } - if (lodSize == defaultLodSize && OBJModel.this.speculars.containsKey(texName)) { - state.specular(OBJModel.this.speculars.get(texName).synchronous(wait)); + + OBJTextureSheet specTex = null; + if (OBJModel.this.speculars.containsKey(texName)) { + Map specLodMap = OBJModel.this.speculars.get(texName); + specTex = specLodMap.get(lodSize); + if (specTex == null) { + specTex = specLodMap.get(defaultLodSize); + } + } + if (specTex != null) { + if (wait) { + state.specular(specTex.synchronous(true)); + } else { + specTex.getId(); + if (!specTex.isLoaded()) { + specTex = OBJModel.this.speculars.get(texName).values().stream() + .filter(CustomTexture::isLoaded) + .findAny().orElse(null); + } + if (specTex != null) { + state.specular(specTex); + } else { + state.specular(defTex); + } + } } else { state.specular(defTex); } + state.smooth_shading(OBJModel.this.isSmoothShading); }