From 2d4f820f04a9bed57fb105b6f1505c31379bdb66 Mon Sep 17 00:00:00 2001
From: lars <larslukasneuhaus@gmx.de>
Date: Sat, 22 Mar 2025 17:28:43 +0100
Subject: [PATCH] added advanced texture support

---
 .idea/modules.xml                             |   1 +
 .../java/eu/mhsl/minecraft/pixelpic/Main.java |  69 +++++++-
 .../render/raytrace/AdvancedRaytracer.java    | 151 ++++++++++++++++++
 .../render/raytrace/DefaultRaytracer.java     |   2 +
 .../registry/AdvancedModelRegistry.java       | 124 +++++++++-----
 src/main/resources/colormap/foliage.png       | Bin 0 -> 14154 bytes
 src/main/resources/colormap/grass.png         | Bin 0 -> 5984 bytes
 7 files changed, 308 insertions(+), 39 deletions(-)
 create mode 100644 src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/AdvancedRaytracer.java
 create mode 100644 src/main/resources/colormap/foliage.png
 create mode 100644 src/main/resources/colormap/grass.png

diff --git a/.idea/modules.xml b/.idea/modules.xml
index 0fe66a1..987850f 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -3,6 +3,7 @@
   <component name="ProjectModuleManager">
     <modules>
       <module fileurl="file://$PROJECT_DIR$/.idea/modules/PixelPic.main.iml" filepath="$PROJECT_DIR$/.idea/modules/PixelPic.main.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/PixelPics.PixelPic.main.iml" filepath="$PROJECT_DIR$/.idea/modules/PixelPics.PixelPic.main.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/modules/eu.mhsl.minecraft.pixelpic.PixelPic.main.iml" filepath="$PROJECT_DIR$/.idea/modules/eu.mhsl.minecraft.pixelpic.PixelPic.main.iml" />
     </modules>
   </component>
diff --git a/src/main/java/eu/mhsl/minecraft/pixelpic/Main.java b/src/main/java/eu/mhsl/minecraft/pixelpic/Main.java
index 7a3d31e..0e04da3 100644
--- a/src/main/java/eu/mhsl/minecraft/pixelpic/Main.java
+++ b/src/main/java/eu/mhsl/minecraft/pixelpic/Main.java
@@ -6,9 +6,16 @@ import eu.mhsl.minecraft.pixelpic.render.render.Renderer;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Bukkit;
 import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
 import org.bukkit.plugin.java.JavaPlugin;
 
-import java.util.Objects;
+import java.io.*;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
 
 public final class Main extends JavaPlugin {
     private static Main instance;
@@ -17,10 +24,27 @@ public final class Main extends JavaPlugin {
     @Override
     public void onEnable() {
         instance = this;
+        extractJsonResources();
+
         Bukkit.getPluginCommand("pixelPic").setExecutor(new PixelPicCommand());
 
         Bukkit.getPluginCommand("test").setExecutor((sender, command, label, args) -> {
+            Material.getMaterial("acacia_button");
             Bukkit.broadcast(Component.text(Material.STONE.getBlockTranslationKey().replace("block.minecraft.", "")));
+
+            if(!(sender instanceof Player player))
+                throw new IllegalStateException("Dieser Command kann nur von einem Spieler ausgeführt werden!");
+
+            File blockDir = new File(getDataFolder(), "models/block");
+            for (File file : blockDir.listFiles()) {
+                String blockName = file.getName().substring(0, file.getName().lastIndexOf('.'));
+                Material material = Material.getMaterial(blockName.toUpperCase());
+                System.out.println(material);
+                if(material == null) {
+                    System.out.println(blockName);
+                }
+            }
+
             return true;
         });
     }
@@ -29,6 +53,49 @@ public final class Main extends JavaPlugin {
     public void onDisable() {
     }
 
+    public void extractJsonResources() {
+        String resourcePath = "models/block/"; // Pfad im JAR
+        File outputDir = new File(getDataFolder(), resourcePath);
+        if (outputDir.exists()) return;
+        outputDir.mkdirs();
+
+        try {
+            URL jarUrl = getClass().getProtectionDomain().getCodeSource().getLocation();
+            File jarFile = new File(jarUrl.toURI());
+
+            try (JarFile jar = new JarFile(jarFile)) {
+                Enumeration<JarEntry> entries = jar.entries();
+
+                while (entries.hasMoreElements()) {
+                    JarEntry entry = entries.nextElement();
+                    String entryName = entry.getName();
+
+                    // Nur JSON-Dateien im gewünschten Ordner
+                    if (entryName.startsWith(resourcePath) && entryName.endsWith(".json")) {
+                        InputStream in = getResource(entryName);
+                        if (in == null) continue;
+
+                        File outFile = new File(getDataFolder(), entryName);
+                        outFile.getParentFile().mkdirs(); // Ordnerstruktur sicherstellen
+
+                        try (OutputStream out = new FileOutputStream(outFile)) {
+                            byte[] buffer = new byte[1024];
+                            int len;
+                            while ((len = in.read(buffer)) != -1) {
+                                out.write(buffer, 0, len);
+                            }
+                            System.out.println("Extrahiert: " + entryName);
+                        }
+
+                        in.close();
+                    }
+                }
+            }
+        } catch (IOException | URISyntaxException e) {
+            e.printStackTrace();
+        }
+    }
+
     public Renderer getScreenRenderer() {
         if(this.screenRenderer == null) this.screenRenderer = new DefaultScreenRenderer();
         return this.screenRenderer;
diff --git a/src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/AdvancedRaytracer.java b/src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/AdvancedRaytracer.java
new file mode 100644
index 0000000..b58a4e4
--- /dev/null
+++ b/src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/AdvancedRaytracer.java
@@ -0,0 +1,151 @@
+package eu.mhsl.minecraft.pixelpic.render.raytrace;
+
+import eu.mhsl.minecraft.pixelpic.render.model.Model;
+import eu.mhsl.minecraft.pixelpic.render.registry.AdvancedModelRegistry;
+import eu.mhsl.minecraft.pixelpic.render.registry.ModelRegistry;
+import eu.mhsl.minecraft.pixelpic.render.util.BlockRaytracer;
+import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
+import eu.mhsl.minecraft.pixelpic.render.util.MathUtil;
+import org.bukkit.Color;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Biome;
+import org.bukkit.block.Block;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.util.Vector;
+
+public class AdvancedRaytracer implements Raytracer {
+    private final int maxDistance;
+    private final int reflectionDepth;
+
+    private final AdvancedModelRegistry textureRegistry;
+    private Block reflectedBlock;
+
+    public AdvancedRaytracer() {
+        this(300, 10);
+    }
+
+    public AdvancedRaytracer(int maxDistance, int reflectionDepth) {
+        this.maxDistance = maxDistance;
+        this.reflectionDepth = reflectionDepth;
+
+        this.textureRegistry = new AdvancedModelRegistry();
+        this.textureRegistry.initialize();
+
+        this.reflectedBlock = null;
+    }
+
+    @Override
+    public int trace(World world, Vector point, Vector direction) {
+        return trace(world, point, direction, reflectionDepth);
+    }
+
+    private int trace(World world, Vector point, Vector direction, int reflectionDepth) {
+        Location loc = point.toLocation(world);
+        loc.setDirection(direction);
+        BlockRaytracer iterator = new BlockRaytracer(loc);
+        int baseColor = Color.fromRGB(65, 89, 252).asRGB();
+        Vector finalIntersection = null;
+
+        int reflectionColor = 0;
+        double reflectionFactor = 0;
+        boolean reflected = false;
+
+        Vector transparencyStart = null;
+        int transparencyColor = 0;
+        double transparencyFactor = 0;
+
+        Material occlusionMaterial = null;
+        BlockData occlusionData = null;
+
+        for (int i = 0; i < maxDistance; i++) {
+            if (!iterator.hasNext()) break;
+            Block block = iterator.next();
+            if (reflectedBlock != null && reflectedBlock.equals(block)) continue;
+            reflectedBlock = null;
+
+            Material material = block.getType();
+            if (material == Material.AIR) {
+                occlusionMaterial = null;
+                occlusionData = null;
+                continue;
+            }
+
+            Model textureModel = textureRegistry.getModel(block.getType(), block.getBlockData(), block.getTemperature(), block.getHumidity());
+            Intersection currentIntersection = Intersection.of(
+                MathUtil.toVector(iterator.getIntersectionFace()),
+                i == 0 ? point : iterator.getIntersectionPoint(),
+                direction
+            );
+            Intersection newIntersection = textureModel.intersect(block, currentIntersection);
+
+            if (newIntersection == null) continue;
+
+            int color = newIntersection.getColor();
+
+            if (!reflected && textureModel.getReflectionFactor() > 0 && reflectionDepth > 0 && (color >> 24) != 0) {
+                reflectedBlock = block;
+                reflectionColor = trace(
+                    world,
+                    newIntersection.getPoint(),
+                    MathUtil.reflectVector(
+                        point,
+                        direction,
+                        newIntersection.getPoint(),
+                        newIntersection.getNormal()
+                    ),
+                    reflectionDepth - 1
+                );
+                reflectionFactor = textureModel.getReflectionFactor();
+                reflected = true;
+            }
+
+            if (transparencyStart == null && textureModel.getTransparencyFactor() > 0) {
+                transparencyStart = newIntersection.getPoint();
+                transparencyColor = newIntersection.getColor();
+                transparencyFactor = textureModel.getTransparencyFactor();
+            }
+
+            if (textureModel.isOccluding()) {
+                BlockData data = block.getBlockData();
+
+                if (material == occlusionMaterial && data.equals(occlusionData)) continue;
+
+                occlusionMaterial = material;
+                occlusionData = data;
+            } else {
+                occlusionMaterial = null;
+                occlusionData = null;
+            }
+
+            if (transparencyStart != null && textureModel.getTransparencyFactor() > 0) continue;
+            if ((color >> 24) == 0) continue;
+
+            baseColor = color;
+            finalIntersection = newIntersection.getPoint();
+            break;
+        }
+
+        if (transparencyStart != null) {
+            baseColor = MathUtil.weightedColorSum(
+                baseColor,
+                transparencyColor,
+                transparencyFactor,
+                (1
+                    - transparencyFactor)
+                    * (1 + transparencyStart.distance(finalIntersection == null ? transparencyStart : finalIntersection)
+                    / 5.0));
+        }
+        if (reflected) {
+            baseColor = MathUtil.weightedColorSum(
+                baseColor,
+                reflectionColor,
+                1 - reflectionFactor,
+                reflectionFactor
+            );
+        }
+
+        return baseColor & 0xFFFFFF;
+    }
+}
diff --git a/src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/DefaultRaytracer.java b/src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/DefaultRaytracer.java
index 621e0a0..7851007 100644
--- a/src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/DefaultRaytracer.java
+++ b/src/main/java/eu/mhsl/minecraft/pixelpic/render/raytrace/DefaultRaytracer.java
@@ -10,6 +10,7 @@ import org.bukkit.Color;
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.World;
+import org.bukkit.block.Biome;
 import org.bukkit.block.Block;
 import org.bukkit.block.data.BlockData;
 import org.bukkit.util.Vector;
@@ -71,6 +72,7 @@ public class DefaultRaytracer implements Raytracer {
                 continue;
             }
 
+            Biome biome = block.getBiome();
             Model textureModel = textureRegistry.getModel(block);
             Intersection currentIntersection = Intersection.of(
                 MathUtil.toVector(iterator.getIntersectionFace()),
diff --git a/src/main/java/eu/mhsl/minecraft/pixelpic/render/registry/AdvancedModelRegistry.java b/src/main/java/eu/mhsl/minecraft/pixelpic/render/registry/AdvancedModelRegistry.java
index a8d8004..80f9218 100644
--- a/src/main/java/eu/mhsl/minecraft/pixelpic/render/registry/AdvancedModelRegistry.java
+++ b/src/main/java/eu/mhsl/minecraft/pixelpic/render/registry/AdvancedModelRegistry.java
@@ -1,5 +1,7 @@
 package eu.mhsl.minecraft.pixelpic.render.registry;
 
+import com.google.gson.Gson;
+import eu.mhsl.minecraft.pixelpic.Main;
 import eu.mhsl.minecraft.pixelpic.render.model.AbstractModel;
 import eu.mhsl.minecraft.pixelpic.render.model.Model;
 import org.bukkit.Color;
@@ -9,28 +11,47 @@ import org.bukkit.block.data.BlockData;
 
 import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.net.URL;
 import java.util.*;
 
 import static eu.mhsl.minecraft.pixelpic.render.registry.DefaultModelRegistry.TEXTURE_SIZE;
 
 public class AdvancedModelRegistry implements ModelRegistry {
+    private final Gson gson = new Gson();
+
     private final Map<Material, Map<BlockData, Model>> modelMap = new HashMap<>();
+    private final Set<String> tintedBlocks = Set.of("grass", "grass_block", "leaves", "oak_leaves", "water", "vine", "sugar_cane");
+
+    public record BlockInfo(String parent, BlockTextures textures){}
+    public record BlockTextures(
+        String texture,
+        String bottom,
+        String top,
+        String all,
+        String particle,
+        String end,
+        String side,
+        String cross,
+        String rail,
+        String overlay
+    ){}
 
     @Override
     public void initialize() {
-//        registerModel(Material.STONE, AbstractModel.Builder.createSimple(getTextureArray(Material.STONE.getBlockTranslationKey().replace("block.minecraft.", ""))).build());
-        for (Material currentMaterial : Material.values()) {
-            if(!currentMaterial.isBlock()) continue;
-            List<String> blockTextures = getBlockTextures(currentMaterial);
-            for (String blockTexture : blockTextures) {
-                try {
-                    registerModel(currentMaterial, AbstractModel.Builder.createSimple(getTextureArray(blockTexture)).build());
-                } catch (Exception ignored) { }
-            }
+        System.out.println(modelMap);
+
+        File blockDir = new File(Main.getInstance().getDataFolder(), "models/block");
+        for (File file : Objects.requireNonNull(blockDir.listFiles())) {
+            addModelFromFile(file);
         }
+
+        try {
+            registerModel(Material.LAVA, AbstractModel.Builder.createSimple(getTextureArray("lava_still"))
+                .transparency(0.15).reflection(0.05).occlusion().build());
+            registerModel(Material.WATER, AbstractModel.Builder.createSimple(getTextureArray("water_still"))
+                .transparency(0.60).reflection(0.1).occlusion().build());
+        } catch (Exception ignored) { }
     }
 
     @Override
@@ -40,6 +61,10 @@ public class AdvancedModelRegistry implements ModelRegistry {
 
     @Override
     public Model getModel(Material material, BlockData blockData) {
+        return getModel(material, blockData, 0.8, 0.4);
+    }
+
+    public Model getModel(Material material, BlockData blockData, double temperature, double humidity) {
         return modelMap.computeIfAbsent(material, key -> new HashMap<>()).getOrDefault(blockData,
             blockData == null ? getDefaultModel()
                 : modelMap.get(material).getOrDefault(null, getDefaultModel()));
@@ -55,39 +80,54 @@ public class AdvancedModelRegistry implements ModelRegistry {
             .put(null, blockModel);
     }
 
-    private List<String> getBlockTextures(Material material) {
-        if(!material.isBlock()) return new ArrayList<>();
-        String blockName = material.name().toLowerCase();
-        try {
-            if(!Arrays.deepEquals(getTextureArray(blockName), new int[0][0])) {
-                return List.of(blockName);
+    private void addModelFromFile(File file) {
+        String blockName = file.getName().substring(0, file.getName().lastIndexOf('.'));
+        Material material = Material.getMaterial(blockName.toUpperCase());
+        if(material == null) return;
+
+        Model model = getModelFromFile(file);
+        if(model == null) return;
+
+        registerModel(material, model);
+    }
+
+    private Model getModelFromFile(File file) {
+        try (Reader reader = new FileReader(file)) {
+            BlockInfo blockInfo = gson.fromJson(reader, BlockInfo.class);
+
+            if(blockInfo.textures.all != null) {
+                return AbstractModel.Builder.createSimple(
+                    getTextureArray(blockInfo.textures.all.substring(blockInfo.textures.all.lastIndexOf('/') + 1))
+                ).build();
+            }
+            if(blockInfo.textures.cross != null) {
+                return AbstractModel.Builder.createCross(
+                    getTextureArray(blockInfo.textures.cross.substring(blockInfo.textures.cross.lastIndexOf('/') + 1))
+                ).build();
+            }
+            if(blockInfo.textures.side != null && blockInfo.textures.bottom != null && blockInfo.textures.top != null) {
+                return AbstractModel.Builder.createMulti(
+                    getTextureArray(blockInfo.textures.top.substring(blockInfo.textures.top.lastIndexOf('/') + 1)),
+                    getTextureArray(blockInfo.textures.side.substring(blockInfo.textures.side.lastIndexOf('/') + 1)),
+                    getTextureArray(blockInfo.textures.bottom.substring(blockInfo.textures.bottom.lastIndexOf('/') + 1))
+                ).build();
+            }
+            if(blockInfo.textures.side != null && blockInfo.textures.end != null) {
+                return AbstractModel.Builder.createMulti(
+                    getTextureArray(blockInfo.textures.end.substring(blockInfo.textures.end.lastIndexOf('/') + 1)),
+                    getTextureArray(blockInfo.textures.side.substring(blockInfo.textures.side.lastIndexOf('/') + 1)),
+                    getTextureArray(blockInfo.textures.end.substring(blockInfo.textures.end.lastIndexOf('/') + 1))
+                ).build();
             }
         } catch (Exception e) {
-            String[] possibleVariants = {
-                blockName + "_top",
-                blockName + "_side",
-                blockName + "_bottom",
-                blockName + "_front",
-                blockName + "_back",
-                blockName + "_left",
-                blockName + "_right"
-            };
-            List<String> results = new ArrayList<>();
-            for (String variant : possibleVariants) {
-                try {
-                    if(!Arrays.deepEquals(getTextureArray(variant), new int[0][0])) {
-                        results.add(variant);
-                    }
-                } catch (Exception ignored) { }
-            }
-            return results;
+            System.out.println(e.getMessage());
         }
-        return new ArrayList<>();
+        return null;
     }
 
     private int[][] getTextureArray(String textureName) {
         int[][] texture = new int[TEXTURE_SIZE][TEXTURE_SIZE];
-        BufferedImage img = null;
+        BufferedImage img;
         URL url = this.getClass().getClassLoader().getResource(String.format("textures/block/%s.png", textureName));
         if (url == null) {
             throw new RuntimeException("Block Texture Resource not found.");
@@ -100,10 +140,18 @@ public class AdvancedModelRegistry implements ModelRegistry {
 
         for (int pixelY = 0; pixelY < TEXTURE_SIZE; pixelY++) {
             for (int pixelX = 0; pixelX < TEXTURE_SIZE; pixelX++) {
-                texture[pixelY][pixelX] = img.getRGB(pixelX, pixelY);
+                texture[TEXTURE_SIZE - 1 - pixelY][TEXTURE_SIZE - 1 - pixelX] = img.getRGB(pixelX, pixelY);
             }
         }
 
         return texture;
     }
+
+    private int tintPixel(int baseColor, int tintColor) {
+        int a = (baseColor >> 24) & 0xFF;
+        int r = ((baseColor >> 16) & 0xFF) * ((tintColor >> 16) & 0xFF) / 255;
+        int g = ((baseColor >> 8) & 0xFF) * ((tintColor >> 8) & 0xFF) / 255;
+        int b = (baseColor & 0xFF) * (tintColor & 0xFF) / 255;
+        return (a << 24) | (r << 16) | (g << 8) | b;
+    }
 }
diff --git a/src/main/resources/colormap/foliage.png b/src/main/resources/colormap/foliage.png
new file mode 100644
index 0000000000000000000000000000000000000000..d58fce229108e9e6e188ed13baa75bc432ead19a
GIT binary patch
literal 14154
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
Ut;h_7$p8QV07*qoM6N<$f=RGsc>n+a

literal 0
HcmV?d00001

diff --git a/src/main/resources/colormap/grass.png b/src/main/resources/colormap/grass.png
new file mode 100644
index 0000000000000000000000000000000000000000..5b946547e675348ee9a864af7000e9de013f8dfa
GIT binary patch
literal 5984
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
O0000<MNUMnLSTZ;JX+BJ

literal 0
HcmV?d00001