Compare commits
5 Commits
master
...
develop-te
Author | SHA1 | Date | |
---|---|---|---|
2d4f820f04 | |||
ab97315910 | |||
c5c21d89b6 | |||
ddbe59a5ac | |||
0103a654c3 |
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@ -3,6 +3,8 @@
|
|||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<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/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>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
4
.idea/modules/PixelPic.main.iml
generated
4
.idea/modules/PixelPic.main.iml
generated
@ -11,4 +11,8 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
</component>
|
</component>
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
</module>
|
</module>
|
14
.idea/modules/eu.mhsl.minecraft.pixelpic.PixelPic.main.iml
generated
Normal file
14
.idea/modules/eu.mhsl.minecraft.pixelpic.PixelPic.main.iml
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="minecraft" name="Minecraft">
|
||||||
|
<configuration>
|
||||||
|
<autoDetectTypes>
|
||||||
|
<platformType>PAPER</platformType>
|
||||||
|
<platformType>ADVENTURE</platformType>
|
||||||
|
</autoDetectTypes>
|
||||||
|
<projectReimportVersion>1</projectReimportVersion>
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,46 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.map.MapCanvas;
|
||||||
|
import org.bukkit.map.MapRenderer;
|
||||||
|
import org.bukkit.map.MapView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
public class ImageMapRenderer extends MapRenderer {
|
||||||
|
public static final int IMAGE_SIZE = 128;
|
||||||
|
private final BufferedImage image;
|
||||||
|
private boolean alreadyRendered = false;
|
||||||
|
|
||||||
|
public ImageMapRenderer(BufferedImage image) {
|
||||||
|
this(image, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageMapRenderer(BufferedImage image, int x, int y) {
|
||||||
|
this.image = recalculateInput(image, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BufferedImage recalculateInput(BufferedImage input, int x, int y) {
|
||||||
|
if (x * IMAGE_SIZE > input.getWidth() || y * IMAGE_SIZE > input.getHeight())
|
||||||
|
throw new RuntimeException(String.format("Input image mus match a multiple of x and y with %d", IMAGE_SIZE));
|
||||||
|
|
||||||
|
int x1 = (int) (double) (x * IMAGE_SIZE);
|
||||||
|
int y1 = (int) (double) (y * IMAGE_SIZE);
|
||||||
|
|
||||||
|
int x2 = (int) (double) Math.min(input.getWidth(), ((x + 1) * IMAGE_SIZE));
|
||||||
|
int y2 = (int) (double) Math.min(input.getHeight(), ((y + 1) * IMAGE_SIZE));
|
||||||
|
|
||||||
|
if (x2 - x1 <= 0 || y2 - y1 <= 0)
|
||||||
|
throw new RuntimeException("Invalid Image dimensions!");
|
||||||
|
|
||||||
|
return input.getSubimage(x1, y1, x2 - x1, y2 - y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player) {
|
||||||
|
if(this.alreadyRendered) return;
|
||||||
|
canvas.drawImage(0, 0, this.image);
|
||||||
|
this.alreadyRendered = true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,107 @@
|
|||||||
package eu.mhsl.minecraft.pixelpic;
|
package eu.mhsl.minecraft.pixelpic;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.commands.PixelPicCommand;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.render.DefaultScreenRenderer;
|
||||||
|
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 org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
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 {
|
public final class Main extends JavaPlugin {
|
||||||
|
private static Main instance;
|
||||||
|
private Renderer screenRenderer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
// Plugin startup logic
|
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;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
// Plugin shutdown logic
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Main getInstance() {
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.commands;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.ImageMapRenderer;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.Main;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.render.Resolution;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.MapMeta;
|
||||||
|
import org.bukkit.map.MapView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class PixelPicCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String @NotNull [] args) {
|
||||||
|
if(!(sender instanceof Player player))
|
||||||
|
throw new IllegalStateException("Dieser Command kann nur von einem Spieler ausgeführt werden!");
|
||||||
|
|
||||||
|
Resolution.Pixels pixels = Resolution.Pixels._128P;
|
||||||
|
Resolution.AspectRatio aspectRatio = Resolution.AspectRatio._1_1;
|
||||||
|
Resolution resolution = new Resolution(pixels, aspectRatio);
|
||||||
|
|
||||||
|
BufferedImage image = Main.getInstance().getScreenRenderer().render(player, resolution);
|
||||||
|
|
||||||
|
File file = new File(Main.getInstance().getDataFolder(), "Bild" + ".png");
|
||||||
|
try {
|
||||||
|
Main.getInstance().getDataFolder().mkdir();
|
||||||
|
ImageIO.write(image, "png", file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack map = new ItemStack(Material.FILLED_MAP, 1);
|
||||||
|
MapMeta meta = (MapMeta) map.getItemMeta();
|
||||||
|
|
||||||
|
MapView mapView = Bukkit.createMap(Bukkit.getWorlds().getFirst());
|
||||||
|
mapView.getRenderers().forEach(mapView::removeRenderer);
|
||||||
|
mapView.addRenderer(new ImageMapRenderer(image));
|
||||||
|
|
||||||
|
meta.setMapView(mapView);
|
||||||
|
map.setItemMeta(meta);
|
||||||
|
|
||||||
|
player.getInventory().addItem(map);
|
||||||
|
player.updateInventory();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.MultiModel.MultiModelBuilder;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.CrossModel.CrossModelBuilder;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.StaticModel.StaticModelBuilder;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.OctahedronModel.OctahedronModelBuilder;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.SphereModel.SphereModelBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class AbstractModel implements Model {
|
||||||
|
|
||||||
|
final int textureSize;
|
||||||
|
final int[][] texture;
|
||||||
|
|
||||||
|
private final double transparencyFactor;
|
||||||
|
private final double reflectionFactor;
|
||||||
|
private final boolean occluding;
|
||||||
|
|
||||||
|
AbstractModel(int[][] texture, double transparencyFactor, double reflectionFactor,
|
||||||
|
boolean occluding) {
|
||||||
|
Preconditions.checkNotNull(texture);
|
||||||
|
Preconditions.checkArgument(texture.length > 0, "texture cannot be empty");
|
||||||
|
Preconditions.checkArgument(texture.length == texture[0].length, "texture must be a square array");
|
||||||
|
|
||||||
|
this.textureSize = texture.length;
|
||||||
|
this.texture = texture;
|
||||||
|
|
||||||
|
this.transparencyFactor = transparencyFactor;
|
||||||
|
this.reflectionFactor = reflectionFactor;
|
||||||
|
this.occluding = occluding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getTransparencyFactor() {
|
||||||
|
return transparencyFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getReflectionFactor() {
|
||||||
|
return reflectionFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOccluding() {
|
||||||
|
return occluding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class Builder {
|
||||||
|
|
||||||
|
final int[][] texture;
|
||||||
|
|
||||||
|
double transparencyFactor;
|
||||||
|
double reflectionFactor;
|
||||||
|
boolean occluding;
|
||||||
|
|
||||||
|
Builder(int[][] texture) {
|
||||||
|
this.texture = texture;
|
||||||
|
|
||||||
|
this.transparencyFactor = 0;
|
||||||
|
this.reflectionFactor = 0;
|
||||||
|
this.occluding = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimpleModel.SimpleModelBuilder createSimple(int[][] texture) {
|
||||||
|
return new SimpleModel.SimpleModelBuilder(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MultiModelBuilder createMulti(int[][] topTexture, int[][] sideTexture,
|
||||||
|
int[][] bottomTexture) {
|
||||||
|
return new MultiModelBuilder(topTexture, sideTexture, bottomTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StaticModelBuilder createStatic(int color) {
|
||||||
|
return new StaticModelBuilder(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CrossModelBuilder createCross(int[][] texture) {
|
||||||
|
return new CrossModelBuilder(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SphereModelBuilder createSphere(int[][] texture) {
|
||||||
|
return new SphereModelBuilder(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OctahedronModelBuilder createOctahedron(int[][] texture) {
|
||||||
|
return new OctahedronModelBuilder(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder transparency(double transparencyFactor) {
|
||||||
|
this.transparencyFactor = transparencyFactor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder reflection(double reflectionFactor) {
|
||||||
|
this.reflectionFactor = reflectionFactor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder occlusion() {
|
||||||
|
this.occluding = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Model build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.MathUtil;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public class CrossModel extends AbstractModel {
|
||||||
|
|
||||||
|
private static final Vector NORMAL_ONE = new Vector(1, 0, 1).normalize();
|
||||||
|
private static final Vector NORMAL_TWO = new Vector(-1, 0, 1).normalize();
|
||||||
|
|
||||||
|
private static final Vector POINT_ONE = new Vector(1, 0, 0);
|
||||||
|
private static final Vector POINT_TWO = new Vector(1, 0, 1);
|
||||||
|
|
||||||
|
private CrossModel(int[][] texture, double transparencyFactor, double reflectionFactor,
|
||||||
|
boolean occluding) {
|
||||||
|
super(texture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intersection intersect(Block block, Intersection currentIntersection) {
|
||||||
|
Vector linePoint = currentIntersection.getPoint();
|
||||||
|
Vector lineDirection = currentIntersection.getDirection();
|
||||||
|
|
||||||
|
Vector blockPoint = block.getLocation().toVector();
|
||||||
|
Vector planePoint = block.getLocation().add(0.5, 0, 0.5).toVector();
|
||||||
|
|
||||||
|
double distance = Double.POSITIVE_INFINITY;
|
||||||
|
int color = 0;
|
||||||
|
Vector target = null;
|
||||||
|
|
||||||
|
Vector intersectionOne = MathUtil.getLinePlaneIntersection(linePoint, lineDirection, planePoint, NORMAL_ONE,
|
||||||
|
true);
|
||||||
|
if (intersectionOne != null) {
|
||||||
|
intersectionOne.subtract(blockPoint);
|
||||||
|
if (isInsideBlock(intersectionOne)) {
|
||||||
|
color = getColor(intersectionOne, POINT_ONE);
|
||||||
|
distance = linePoint.distanceSquared(intersectionOne.add(blockPoint));
|
||||||
|
target = intersectionOne;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector intersectionTwo = MathUtil.getLinePlaneIntersection(linePoint, lineDirection, planePoint, NORMAL_TWO,
|
||||||
|
true);
|
||||||
|
if (intersectionTwo != null) {
|
||||||
|
intersectionTwo.subtract(blockPoint);
|
||||||
|
if (isInsideBlock(intersectionTwo)) {
|
||||||
|
int colorTwo = getColor(intersectionTwo, POINT_TWO);
|
||||||
|
double distanceTwo = linePoint.distanceSquared(intersectionTwo.add(blockPoint));
|
||||||
|
if ((distanceTwo < distance && (colorTwo >> 24) != 0) || (color >> 24) == 0) {
|
||||||
|
target = intersectionTwo;
|
||||||
|
color = colorTwo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
target = linePoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Intersection.of(currentIntersection.getNormal(), target, lineDirection, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInsideBlock(Vector vec) {
|
||||||
|
return vec.getX() >= 0 && vec.getZ() < 1 && vec.getY() >= 0 && vec.getY() < 1 && vec.getZ() >= 0
|
||||||
|
&& vec.getZ() < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getColor(Vector vec, Vector base) {
|
||||||
|
double xOffset = Math.sqrt(Math.pow(vec.getX() - base.getX(), 2) + Math.pow(vec.getZ() - base.getZ(), 2));
|
||||||
|
double yOffset = vec.getY();
|
||||||
|
|
||||||
|
int pixelY = (int) Math.floor(yOffset * textureSize);
|
||||||
|
int pixelX = (int) Math.floor(xOffset / Math.sqrt(2) * textureSize);
|
||||||
|
|
||||||
|
return texture[pixelY][pixelX];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CrossModelBuilder extends Builder {
|
||||||
|
|
||||||
|
CrossModelBuilder(int[][] texture) {
|
||||||
|
super(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CrossModel build() {
|
||||||
|
return new CrossModel(texture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
|
public interface Model {
|
||||||
|
|
||||||
|
Intersection intersect(Block block, Intersection currentIntersection);
|
||||||
|
|
||||||
|
double getTransparencyFactor();
|
||||||
|
|
||||||
|
double getReflectionFactor();
|
||||||
|
|
||||||
|
boolean isOccluding();
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public class MultiModel extends SimpleModel {
|
||||||
|
|
||||||
|
private final int[][] topTexture;
|
||||||
|
private final int[][] bottomTexture;
|
||||||
|
|
||||||
|
private MultiModel(int[][] topTexture, int[][] sideTexture, int[][] bottomTexture,
|
||||||
|
double transparencyFactor, double reflectionFactor, boolean occluding) {
|
||||||
|
super(sideTexture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
|
||||||
|
this.topTexture = topTexture;
|
||||||
|
this.bottomTexture = bottomTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intersection intersect(Block block, Intersection currentIntersection) {
|
||||||
|
if (!currentIntersection.getNormal().equals(UP) && !currentIntersection.getNormal().equals(DOWN)) {
|
||||||
|
return super.intersect(block, currentIntersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector normal = currentIntersection.getNormal();
|
||||||
|
Vector point = currentIntersection.getPoint();
|
||||||
|
Vector direction = currentIntersection.getDirection();
|
||||||
|
|
||||||
|
double yOffset = point.getX() - (int) point.getX();
|
||||||
|
double xOffset = point.getZ() - (int) point.getZ();
|
||||||
|
|
||||||
|
int pixelY = (int) Math.floor((yOffset < 0 ? yOffset + 1 : yOffset) * textureSize);
|
||||||
|
int pixelX = (int) Math.floor((xOffset < 0 ? xOffset + 1 : xOffset) * textureSize);
|
||||||
|
|
||||||
|
if (normal.equals(UP)) {
|
||||||
|
return Intersection.of(normal, point, direction, topTexture[pixelY][pixelX]);
|
||||||
|
} else {
|
||||||
|
return Intersection.of(normal, point, direction, bottomTexture[pixelY][pixelX]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MultiModelBuilder extends SimpleModelBuilder {
|
||||||
|
|
||||||
|
private final int[][] topTexture;
|
||||||
|
private final int[][] bottomTexture;
|
||||||
|
|
||||||
|
MultiModelBuilder(int[][] topTexture, int[][] sideTexture, int[][] bottomTexture) {
|
||||||
|
super(sideTexture);
|
||||||
|
|
||||||
|
this.topTexture = topTexture;
|
||||||
|
this.bottomTexture = bottomTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiModel build() {
|
||||||
|
return new MultiModel(topTexture, texture, bottomTexture, transparencyFactor,
|
||||||
|
reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.MathUtil;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public class OctahedronModel extends AbstractModel {
|
||||||
|
|
||||||
|
private static final double RADIUS = 0.5;
|
||||||
|
|
||||||
|
private static final Vector[] NORMALS = new Vector[]{new Vector(-1, -1, -1), new Vector(-1, -1, 1),
|
||||||
|
new Vector(-1, 1, -1), new Vector(-1, 1, 1), new Vector(1, -1, -1), new Vector(1, -1, 1),
|
||||||
|
new Vector(1, 1, -1), new Vector(1, 1, 1)};
|
||||||
|
|
||||||
|
private OctahedronModel(int[][] texture, double transparencyFactor, double reflectionFactor,
|
||||||
|
boolean occluding) {
|
||||||
|
super(texture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intersection intersect(Block block, Intersection currentIntersection) {
|
||||||
|
Vector linePoint = currentIntersection.getPoint();
|
||||||
|
Vector lineDirection = currentIntersection.getDirection();
|
||||||
|
Vector blockPoint = block.getLocation().toVector();
|
||||||
|
Vector centerPoint = blockPoint.clone().add(new Vector(0.5, 0.5, 0.5));
|
||||||
|
|
||||||
|
Vector lastIntersection = null;
|
||||||
|
double lastDistance = Double.POSITIVE_INFINITY;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
Vector planePoint = new Vector(i < 4 ? -0.5 : 0.5, 0, 0).add(centerPoint);
|
||||||
|
Vector planeNormal = NORMALS[i];
|
||||||
|
|
||||||
|
Vector intersection = MathUtil.getLinePlaneIntersection(linePoint, lineDirection, planePoint, planeNormal,
|
||||||
|
false);
|
||||||
|
if (intersection == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isInsideBlock(blockPoint, planeNormal, intersection)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double distance = intersection.distance(linePoint);
|
||||||
|
if (distance < lastDistance) {
|
||||||
|
lastIntersection = intersection;
|
||||||
|
lastDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastIntersection == null) {
|
||||||
|
return currentIntersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dist = linePoint.distance(centerPoint);
|
||||||
|
double minDist = dist - RADIUS;
|
||||||
|
double maxDist = dist + RADIUS;
|
||||||
|
double factor = (lastDistance - minDist) / (maxDist - minDist);
|
||||||
|
|
||||||
|
double yOffset = lastIntersection.getX() - (int) lastIntersection.getX();
|
||||||
|
double xOffset = lastIntersection.getZ() - (int) lastIntersection.getZ();
|
||||||
|
|
||||||
|
int pixelY = (int) Math.floor((yOffset < 0 ? yOffset + 1 : yOffset) * textureSize);
|
||||||
|
int pixelX = (int) Math.floor((xOffset < 0 ? xOffset + 1 : xOffset) * textureSize);
|
||||||
|
|
||||||
|
return Intersection.of(currentIntersection.getNormal(), lastIntersection, lineDirection,
|
||||||
|
0xFF000000 | MathUtil.weightedColorSum(texture[pixelY][pixelX], 0, 1 - factor, factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInsideBlock(Vector blockPoint, Vector planeNormal, Vector intersection) {
|
||||||
|
intersection = intersection.clone().subtract(blockPoint);
|
||||||
|
|
||||||
|
if (intersection.getX() < 0 || intersection.getX() >= 1 || intersection.getY() < 0 || intersection.getY() >= 1
|
||||||
|
|| intersection.getZ() < 0 || intersection.getZ() >= 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean posX = planeNormal.getX() >= 0;
|
||||||
|
boolean posY = planeNormal.getY() >= 0;
|
||||||
|
boolean posZ = planeNormal.getZ() >= 0;
|
||||||
|
|
||||||
|
boolean blockX = intersection.getX() >= 0.5;
|
||||||
|
boolean blockY = intersection.getY() >= 0.5;
|
||||||
|
boolean blockZ = intersection.getZ() >= 0.5;
|
||||||
|
|
||||||
|
return posX == blockX && posY == blockY && posZ == blockZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OctahedronModelBuilder extends Builder {
|
||||||
|
|
||||||
|
OctahedronModelBuilder(int[][] texture) {
|
||||||
|
super(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model build() {
|
||||||
|
return new OctahedronModel(texture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public class SimpleModel extends AbstractModel {
|
||||||
|
|
||||||
|
static final Vector UP = new Vector(0, 1, 0);
|
||||||
|
static final Vector DOWN = new Vector(0, -1, 0);
|
||||||
|
private static final Vector NORTH = new Vector(0, 0, -1);
|
||||||
|
private static final Vector SOUTH = new Vector(0, 0, 1);
|
||||||
|
private static final Vector EAST = new Vector(1, 0, 0);
|
||||||
|
private static final Vector WEST = new Vector(-1, 0, 0);
|
||||||
|
|
||||||
|
SimpleModel(int[][] texture, double transparencyFactor, double reflectionFactor,
|
||||||
|
boolean occluding) {
|
||||||
|
super(texture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intersection intersect(Block block, Intersection currentIntersection) {
|
||||||
|
double yOffset;
|
||||||
|
double xOffset;
|
||||||
|
|
||||||
|
Vector normal = currentIntersection.getNormal();
|
||||||
|
Vector point = currentIntersection.getPoint();
|
||||||
|
Vector direction = currentIntersection.getDirection();
|
||||||
|
|
||||||
|
if (normal.equals(NORTH) || normal.equals(SOUTH)) {
|
||||||
|
yOffset = point.getY() - (int) point.getY();
|
||||||
|
xOffset = point.getX() - (int) point.getX();
|
||||||
|
} else if (normal.equals(EAST) || normal.equals(WEST)) {
|
||||||
|
yOffset = point.getY() - (int) point.getY();
|
||||||
|
xOffset = point.getZ() - (int) point.getZ();
|
||||||
|
} else {
|
||||||
|
yOffset = point.getX() - (int) point.getX();
|
||||||
|
xOffset = point.getZ() - (int) point.getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int pixelY = (int) Math.floor((yOffset < 0 ? yOffset + 1 : yOffset) * textureSize);
|
||||||
|
int pixelX = (int) Math.floor((xOffset < 0 ? xOffset + 1 : xOffset) * textureSize);
|
||||||
|
|
||||||
|
return Intersection.of(normal, point, direction, texture[pixelY][pixelX]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SimpleModelBuilder extends Builder {
|
||||||
|
|
||||||
|
protected SimpleModelBuilder(int[][] texture) {
|
||||||
|
super(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model build() {
|
||||||
|
return new SimpleModel(texture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.MathUtil;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public class SphereModel extends AbstractModel {
|
||||||
|
|
||||||
|
private final double radius;
|
||||||
|
private final Vector offset;
|
||||||
|
|
||||||
|
private SphereModel(int[][] texture, double transparencyFactor, double reflectionFactor,
|
||||||
|
boolean occluding, double radius, Vector offset) {
|
||||||
|
super(texture, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
|
||||||
|
this.radius = radius;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intersection intersect(Block block, Intersection currentIntersection) {
|
||||||
|
Vector linePoint = currentIntersection.getPoint();
|
||||||
|
Vector lineDirection = currentIntersection.getDirection();
|
||||||
|
Vector blockPoint = block.getLocation().toVector();
|
||||||
|
Vector centerPoint = block.getLocation().add(0.5, 0.5, 0.5).add(offset).toVector();
|
||||||
|
|
||||||
|
double a = lineDirection.dot(lineDirection);
|
||||||
|
double b = 2 * (linePoint.dot(lineDirection) - centerPoint.dot(lineDirection));
|
||||||
|
double c = linePoint.dot(linePoint) - 2 * centerPoint.dot(linePoint) + centerPoint.dot(centerPoint)
|
||||||
|
- Math.pow(radius, 2);
|
||||||
|
|
||||||
|
double delta = Math.pow(b, 2) - 4 * a * c;
|
||||||
|
if (delta < 0) {
|
||||||
|
return Intersection.of(currentIntersection.getNormal(), linePoint, lineDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
double dist = linePoint.distance(centerPoint);
|
||||||
|
double minDist = dist - radius;
|
||||||
|
double maxDist = dist + radius;
|
||||||
|
|
||||||
|
if (delta == 0) {
|
||||||
|
double t = -b / (2 * a);
|
||||||
|
Vector intersection = lineDirection.clone().add(lineDirection.clone().multiply(t));
|
||||||
|
if (!isInsideBlock(blockPoint, intersection)) {
|
||||||
|
return currentIntersection;
|
||||||
|
}
|
||||||
|
double currentDist = intersection.distance(linePoint);
|
||||||
|
double factor = (currentDist - minDist) / (maxDist - minDist);
|
||||||
|
Vector normal = intersection.clone().subtract(centerPoint).normalize();
|
||||||
|
return Intersection.of(normal, intersection, lineDirection, getColor(centerPoint, intersection, factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
double deltaSqrt = Math.sqrt(delta);
|
||||||
|
|
||||||
|
double tOne = (-b + deltaSqrt) / (2 * a);
|
||||||
|
double tTwo = (-b - deltaSqrt) / (2 * a);
|
||||||
|
|
||||||
|
Vector intersectionOne = linePoint.clone().add(lineDirection.clone().multiply(tOne));
|
||||||
|
Vector intersectionTwo = linePoint.clone().add(lineDirection.clone().multiply(tTwo));
|
||||||
|
|
||||||
|
boolean first = intersectionOne.distanceSquared(linePoint) < intersectionTwo.distanceSquared(linePoint);
|
||||||
|
double currentDist = (first ? intersectionOne : intersectionTwo).distance(linePoint);
|
||||||
|
double factor = (currentDist - minDist) / (maxDist - minDist);
|
||||||
|
if (first && isInsideBlock(blockPoint, intersectionOne)) {
|
||||||
|
Vector normal = intersectionOne.clone().subtract(centerPoint).normalize();
|
||||||
|
return Intersection.of(normal, intersectionOne, lineDirection,
|
||||||
|
getColor(centerPoint, intersectionOne, factor));
|
||||||
|
} else if (isInsideBlock(blockPoint, intersectionTwo)) {
|
||||||
|
Vector normal = intersectionTwo.clone().subtract(centerPoint).normalize();
|
||||||
|
return Intersection.of(normal, intersectionTwo, lineDirection,
|
||||||
|
getColor(centerPoint, intersectionTwo, factor));
|
||||||
|
} else {
|
||||||
|
return currentIntersection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getColor(Vector base, Vector intersection, double factor) {
|
||||||
|
Location loc = base.toLocation(null);
|
||||||
|
loc.setDirection(intersection.clone().subtract(base).normalize());
|
||||||
|
|
||||||
|
double perimeter = Math.round(2 * Math.PI * radius);
|
||||||
|
double yawDiv = 360 / perimeter;
|
||||||
|
double pitchDiv = 180 / perimeter;
|
||||||
|
|
||||||
|
int pixelX = (int) ((loc.getYaw() % yawDiv) / (yawDiv / textureSize));
|
||||||
|
int pixelY = (int) (((loc.getPitch() + 90) % pitchDiv) / (pitchDiv / textureSize));
|
||||||
|
|
||||||
|
return 0xFF000000 | MathUtil.weightedColorSum(texture[pixelY][pixelX], 0, 1 - factor, factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInsideBlock(Vector blockPoint, Vector intersection) {
|
||||||
|
intersection = intersection.clone().subtract(blockPoint);
|
||||||
|
|
||||||
|
return intersection.getX() >= 0 && intersection.getX() < 1 && intersection.getY() >= 0
|
||||||
|
&& intersection.getY() < 1 && intersection.getZ() >= 0 && intersection.getZ() < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SphereModelBuilder extends Builder {
|
||||||
|
|
||||||
|
private double radius;
|
||||||
|
private Vector offset;
|
||||||
|
|
||||||
|
SphereModelBuilder(int[][] texture) {
|
||||||
|
super(texture);
|
||||||
|
|
||||||
|
this.radius = 0.5;
|
||||||
|
this.offset = new Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SphereModelBuilder radius(double radius) {
|
||||||
|
this.radius = radius;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SphereModelBuilder offset(Vector offset) {
|
||||||
|
this.offset = offset.clone();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model build() {
|
||||||
|
return new SphereModel(texture, transparencyFactor, reflectionFactor, occluding, radius,
|
||||||
|
offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.model;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.AbstractModel.Builder;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.Intersection;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
|
public class StaticModel implements Model {
|
||||||
|
|
||||||
|
private final int color;
|
||||||
|
private final double transparencyFactor;
|
||||||
|
private final double reflectionFactor;
|
||||||
|
private final boolean occluding;
|
||||||
|
|
||||||
|
private StaticModel(int color, double transparencyFactor, double reflectionFactor, boolean occluding) {
|
||||||
|
this.color = color;
|
||||||
|
this.transparencyFactor = transparencyFactor;
|
||||||
|
this.reflectionFactor = reflectionFactor;
|
||||||
|
this.occluding = occluding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intersection intersect(Block block, Intersection currentIntersection) {
|
||||||
|
return Intersection.of(currentIntersection.getNormal(), currentIntersection.getPoint(),
|
||||||
|
currentIntersection.getDirection(), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getTransparencyFactor() {
|
||||||
|
return transparencyFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getReflectionFactor() {
|
||||||
|
return reflectionFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOccluding() {
|
||||||
|
return occluding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StaticModelBuilder extends Builder {
|
||||||
|
|
||||||
|
private final int color;
|
||||||
|
|
||||||
|
StaticModelBuilder(int color) {
|
||||||
|
super(new int[1][1]);
|
||||||
|
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StaticModel build() {
|
||||||
|
return new StaticModel(color, transparencyFactor, reflectionFactor, occluding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
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 DefaultRaytracer implements Raytracer {
|
||||||
|
private final int maxDistance;
|
||||||
|
private final int reflectionDepth;
|
||||||
|
|
||||||
|
private final ModelRegistry textureRegistry;
|
||||||
|
private Block reflectedBlock;
|
||||||
|
|
||||||
|
public DefaultRaytracer() {
|
||||||
|
this(300, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultRaytracer(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Biome biome = block.getBiome();
|
||||||
|
Model textureModel = textureRegistry.getModel(block);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.raytrace;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public interface Raytracer {
|
||||||
|
|
||||||
|
int trace(World world, Vector point, Vector direction);
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
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;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
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() {
|
||||||
|
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
|
||||||
|
public Model getModel(Block block) {
|
||||||
|
return ModelRegistry.super.getModel(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getDefaultModel() {
|
||||||
|
return AbstractModel.Builder.createStatic(Color.PURPLE.asRGB()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerModel(Material material, Model blockModel) {
|
||||||
|
modelMap.computeIfAbsent(material, key -> new HashMap<>())
|
||||||
|
.put(null, blockModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[][] getTextureArray(String textureName) {
|
||||||
|
int[][] texture = new int[TEXTURE_SIZE][TEXTURE_SIZE];
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
try (InputStream input = url.openConnection().getInputStream()) {
|
||||||
|
img = ImageIO.read(input);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int pixelY = 0; pixelY < TEXTURE_SIZE; pixelY++) {
|
||||||
|
for (int pixelX = 0; pixelX < TEXTURE_SIZE; pixelX++) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.registry;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.AbstractModel.Builder;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.Model;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
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.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DefaultModelRegistry implements ModelRegistry {
|
||||||
|
|
||||||
|
private static final String IMAGE_RESOURCE = "terrain.png";
|
||||||
|
static final int TEXTURE_SIZE = 16;
|
||||||
|
|
||||||
|
private final Map<Material, Map<BlockData, Model>> modelMap;
|
||||||
|
private BufferedImage textures;
|
||||||
|
|
||||||
|
public DefaultModelRegistry() {
|
||||||
|
this.modelMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
URL url = this.getClass().getClassLoader().getResource(IMAGE_RESOURCE);
|
||||||
|
if (url == null) {
|
||||||
|
throw new RuntimeException("Default resource \"terrain.png\" is missing");
|
||||||
|
}
|
||||||
|
try (InputStream input = url.openConnection().getInputStream()) {
|
||||||
|
this.textures = ImageIO.read(input);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerModel(Material.GRASS_BLOCK, Builder.createMulti(textureIndex(0, 0), textureIndex(0, 3), textureIndex(0, 2)).build());
|
||||||
|
registerModel(Material.STONE, Builder.createSimple(textureIndex(0, 1)).build());
|
||||||
|
registerModel(Material.DIRT, Builder.createSimple(textureIndex(0, 2)).build());
|
||||||
|
registerModel(Material.OAK_PLANKS, Builder.createSimple(textureIndex(0, 4)).build());
|
||||||
|
registerModel(Material.SPRUCE_PLANKS,
|
||||||
|
Builder.createSimple(textureIndex(0, 4)).build());
|
||||||
|
registerModel(Material.BIRCH_PLANKS,
|
||||||
|
Builder.createSimple(textureIndex(0, 4)).build());
|
||||||
|
registerModel(Material.JUNGLE_PLANKS,
|
||||||
|
Builder.createSimple(textureIndex(0, 4)).build());
|
||||||
|
registerModel(Material.ACACIA_PLANKS,
|
||||||
|
Builder.createSimple(textureIndex(0, 4)).build());
|
||||||
|
registerModel(Material.DARK_OAK_PLANKS,
|
||||||
|
Builder.createSimple(textureIndex(0, 4)).build());
|
||||||
|
registerModel(Material.BRICK, Builder.createSimple(textureIndex(0, 7)).build());
|
||||||
|
registerModel(Material.TNT, Builder.createMulti(textureIndex(0, 9),
|
||||||
|
textureIndex(0, 8), textureIndex(0, 10)).build());
|
||||||
|
registerModel(Material.WATER, Builder.createStatic(0xFF000000 | Color.fromRGB(0, 5, 60).asRGB())
|
||||||
|
.transparency(0.60).reflection(0.1).occlusion().build());
|
||||||
|
registerModel(Material.DIAMOND_BLOCK,
|
||||||
|
Builder.createSimple(textureIndex(3, 3)).reflection(0.75).build());
|
||||||
|
registerModel(Material.POPPY, Builder.createCross(textureIndex(0, 12)).build());
|
||||||
|
registerModel(Material.DANDELION, Builder.createCross(textureIndex(0, 13)).build());
|
||||||
|
registerModel(Material.OAK_SAPLING,
|
||||||
|
Builder.createCross(textureIndex(0, 15)).build());
|
||||||
|
registerModel(Material.SPRUCE_SAPLING,
|
||||||
|
Builder.createCross(textureIndex(0, 15)).build());
|
||||||
|
registerModel(Material.BIRCH_SAPLING,
|
||||||
|
Builder.createCross(textureIndex(0, 15)).build());
|
||||||
|
registerModel(Material.JUNGLE_SAPLING,
|
||||||
|
Builder.createCross(textureIndex(0, 15)).build());
|
||||||
|
registerModel(Material.ACACIA_SAPLING,
|
||||||
|
Builder.createCross(textureIndex(0, 15)).build());
|
||||||
|
registerModel(Material.DARK_OAK_SAPLING,
|
||||||
|
Builder.createCross(textureIndex(0, 15)).build());
|
||||||
|
|
||||||
|
registerModel(Material.COBBLESTONE,
|
||||||
|
Builder.createSimple(textureIndex(1, 0)).build());
|
||||||
|
registerModel(Material.BEDROCK, Builder.createSimple(textureIndex(1, 1)).build());
|
||||||
|
registerModel(Material.SAND, Builder.createSimple(textureIndex(1, 2)).build());
|
||||||
|
registerModel(Material.GRAVEL, Builder.createSimple(textureIndex(1, 3)).build());
|
||||||
|
registerModel(Material.OAK_LOG, Builder.createMulti(textureIndex(1, 5),
|
||||||
|
textureIndex(1, 4), textureIndex(1, 5)).build());
|
||||||
|
registerModel(Material.SPRUCE_LOG, Builder.createMulti(textureIndex(1, 5),
|
||||||
|
textureIndex(1, 4), textureIndex(1, 5)).build());
|
||||||
|
registerModel(Material.BIRCH_LOG, Builder.createMulti(textureIndex(1, 5),
|
||||||
|
textureIndex(1, 4), textureIndex(1, 5)).build());
|
||||||
|
registerModel(Material.JUNGLE_LOG, Builder.createMulti(textureIndex(1, 5),
|
||||||
|
textureIndex(1, 4), textureIndex(1, 5)).build());
|
||||||
|
registerModel(Material.ACACIA_LOG, Builder.createMulti(textureIndex(1, 5),
|
||||||
|
textureIndex(1, 4), textureIndex(1, 5)).build());
|
||||||
|
registerModel(Material.DARK_OAK_LOG, Builder.createMulti(textureIndex(1, 5),
|
||||||
|
textureIndex(1, 4), textureIndex(1, 5)).build());
|
||||||
|
registerModel(Material.OAK_WOOD, Builder.createSimple(textureIndex(1, 4)).build());
|
||||||
|
registerModel(Material.SPRUCE_WOOD,
|
||||||
|
Builder.createSimple(textureIndex(1, 4)).build());
|
||||||
|
registerModel(Material.BIRCH_WOOD, Builder.createSimple(textureIndex(1, 4)).build());
|
||||||
|
registerModel(Material.JUNGLE_WOOD,
|
||||||
|
Builder.createSimple(textureIndex(1, 4)).build());
|
||||||
|
registerModel(Material.ACACIA_WOOD,
|
||||||
|
Builder.createSimple(textureIndex(1, 4)).build());
|
||||||
|
registerModel(Material.DARK_OAK_WOOD,
|
||||||
|
Builder.createSimple(textureIndex(1, 4)).build());
|
||||||
|
registerModel(Material.OAK_LEAVES, Builder.createSimple(textureIndex(1, 6)).build());
|
||||||
|
registerModel(Material.SPRUCE_LEAVES,
|
||||||
|
Builder.createSimple(textureIndex(1, 6)).build());
|
||||||
|
registerModel(Material.BIRCH_LEAVES,
|
||||||
|
Builder.createSimple(textureIndex(1, 6)).build());
|
||||||
|
registerModel(Material.JUNGLE_LEAVES,
|
||||||
|
Builder.createSimple(textureIndex(1, 6)).build());
|
||||||
|
registerModel(Material.ACACIA_LEAVES,
|
||||||
|
Builder.createSimple(textureIndex(1, 6)).build());
|
||||||
|
registerModel(Material.DARK_OAK_LEAVES,
|
||||||
|
Builder.createSimple(textureIndex(1, 6)).build());
|
||||||
|
registerModel(Material.IRON_BLOCK,
|
||||||
|
Builder.createMulti(textureIndex(1, 7),
|
||||||
|
textureIndex(2, 7), textureIndex(3, 7)).build());
|
||||||
|
registerModel(Material.GOLD_BLOCK, Builder.createMulti(textureIndex(1, 8),
|
||||||
|
textureIndex(2, 8), textureIndex(3, 8)).build());
|
||||||
|
registerModel(Material.RED_MUSHROOM,
|
||||||
|
Builder.createCross(textureIndex(1, 12)).build());
|
||||||
|
registerModel(Material.BROWN_MUSHROOM,
|
||||||
|
Builder.createCross(textureIndex(1, 13)).build());
|
||||||
|
registerModel(Material.LAVA, Builder.createSimple(textureIndex(2, 14))
|
||||||
|
.transparency(0.15).reflection(0.05).occlusion().build());
|
||||||
|
|
||||||
|
registerModel(Material.GOLD_ORE, Builder.createSimple(textureIndex(2, 0)).build());
|
||||||
|
registerModel(Material.IRON_ORE, Builder.createSimple(textureIndex(2, 1)).build());
|
||||||
|
registerModel(Material.COAL_ORE, Builder.createSimple(textureIndex(2, 2)).build());
|
||||||
|
|
||||||
|
registerModel(Material.GLASS,
|
||||||
|
Builder.createSimple(textureIndex(3, 1)).occlusion().build());
|
||||||
|
|
||||||
|
registerModel(Material.SHORT_GRASS, Builder.createCross(textureIndex(5, 6)).build());
|
||||||
|
registerModel(Material.SUGAR_CANE, Builder.createCross(textureIndex(5, 5)).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getModel(Material material, BlockData blockData) {
|
||||||
|
return modelMap.computeIfAbsent(material, key -> new HashMap<>()).getOrDefault(blockData,
|
||||||
|
blockData == null ? getDefaultModel()
|
||||||
|
: modelMap.get(material).getOrDefault(null, getDefaultModel()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model getDefaultModel() {
|
||||||
|
return Builder.createStatic(Color.PURPLE.asRGB()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerModel(Material material, Model blockModel) {
|
||||||
|
modelMap.computeIfAbsent(material, key -> new HashMap<>())
|
||||||
|
.put(null, blockModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[][] textureIndex(int verticalIndex, int horizontalIndex) {
|
||||||
|
int[][] texture = new int[TEXTURE_SIZE][TEXTURE_SIZE];
|
||||||
|
|
||||||
|
int offsetY = verticalIndex * TEXTURE_SIZE + (TEXTURE_SIZE - 1);
|
||||||
|
int offsetX = horizontalIndex * TEXTURE_SIZE;
|
||||||
|
|
||||||
|
for (int pixelY = 0; pixelY < TEXTURE_SIZE; pixelY++) {
|
||||||
|
for (int pixelX = 0; pixelX < TEXTURE_SIZE; pixelX++) {
|
||||||
|
texture[pixelY][pixelX] = textures.getRGB(offsetX + pixelX, offsetY - pixelY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.registry;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.model.Model;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
|
||||||
|
public interface ModelRegistry {
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
default Model getModel(Block block) {
|
||||||
|
return getModel(block.getType(), block.getBlockData());
|
||||||
|
}
|
||||||
|
|
||||||
|
default Model getModel(Material material) {
|
||||||
|
return getModel(material, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Model getModel(Material material, BlockData blockData);
|
||||||
|
|
||||||
|
Model getDefaultModel();
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.render;
|
||||||
|
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.raytrace.DefaultRaytracer;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.raytrace.Raytracer;
|
||||||
|
import eu.mhsl.minecraft.pixelpic.render.util.MathUtil;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.DataBufferInt;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DefaultScreenRenderer implements Renderer {
|
||||||
|
|
||||||
|
private static final double FOV_YAW_DEG = 53;
|
||||||
|
private static final double FOV_PITCH_DEG = 23;
|
||||||
|
|
||||||
|
private static final double FOV_YAW_RAD = Math.toRadians(FOV_YAW_DEG);
|
||||||
|
private static final double FOV_PITCH_RAD = Math.toRadians(FOV_PITCH_DEG);
|
||||||
|
|
||||||
|
private static final Vector BASE_VEC = new Vector(1, 0, 0);
|
||||||
|
|
||||||
|
private final Raytracer raytracer;
|
||||||
|
|
||||||
|
public DefaultScreenRenderer() {
|
||||||
|
this.raytracer = new DefaultRaytracer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferedImage render(Player player, Resolution resolution) {
|
||||||
|
int width = resolution.getWidth();
|
||||||
|
int height = resolution.getHeight();
|
||||||
|
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||||
|
int[] imageData = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||||
|
|
||||||
|
World world = player.getWorld();
|
||||||
|
Vector linePoint = player.getEyeLocation().toVector();
|
||||||
|
List<Vector> rayMap = buildRayMap(player, resolution);
|
||||||
|
for (int i = 0; i < rayMap.size(); i++) {
|
||||||
|
imageData[i] = raytracer.trace(world, linePoint, rayMap.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Vector> buildRayMap(Player p, Resolution resolution) {
|
||||||
|
Location eyeLocation = p.getEyeLocation();
|
||||||
|
Vector lineDirection = eyeLocation.getDirection();
|
||||||
|
|
||||||
|
double x = lineDirection.getX();
|
||||||
|
double y = lineDirection.getY();
|
||||||
|
double z = lineDirection.getZ();
|
||||||
|
|
||||||
|
double angleYaw = Math.atan2(z, x);
|
||||||
|
double anglePitch = Math.atan2(y, Math.sqrt(x * x + z * z));
|
||||||
|
|
||||||
|
Vector lowerLeftCorner = MathUtil.doubleYawPitchRotation(BASE_VEC, -FOV_YAW_RAD, -FOV_PITCH_RAD, angleYaw, anglePitch);
|
||||||
|
Vector upperLeftCorner = MathUtil.doubleYawPitchRotation(BASE_VEC, -FOV_YAW_RAD, FOV_PITCH_RAD, angleYaw, anglePitch);
|
||||||
|
Vector lowerRightCorner = MathUtil.doubleYawPitchRotation(BASE_VEC, FOV_YAW_RAD, -FOV_PITCH_RAD, angleYaw, anglePitch);
|
||||||
|
Vector upperRightCorner = MathUtil.doubleYawPitchRotation(BASE_VEC, FOV_YAW_RAD, FOV_PITCH_RAD, angleYaw, anglePitch);
|
||||||
|
|
||||||
|
int width = resolution.getWidth();
|
||||||
|
int height = resolution.getHeight();
|
||||||
|
List<Vector> rayMap = new ArrayList<>(width * height);
|
||||||
|
|
||||||
|
Vector leftFraction = upperLeftCorner.clone().subtract(lowerLeftCorner).multiply(1.0 / (height - 1));
|
||||||
|
Vector rightFraction = upperRightCorner.clone().subtract(lowerRightCorner).multiply(1.0 / (height - 1));
|
||||||
|
|
||||||
|
for (int pitch = 0; pitch < height; pitch++) {
|
||||||
|
|
||||||
|
Vector leftPitch = upperLeftCorner.clone().subtract(leftFraction.clone().multiply(pitch));
|
||||||
|
Vector rightPitch = upperRightCorner.clone().subtract(rightFraction.clone().multiply(pitch));
|
||||||
|
Vector yawFraction = rightPitch.clone().subtract(leftPitch).multiply(1.0 / (width - 1));
|
||||||
|
|
||||||
|
for (int yaw = 0; yaw < width; yaw++) {
|
||||||
|
Vector ray = leftPitch.clone().add(yawFraction.clone().multiply(yaw)).normalize();
|
||||||
|
rayMap.add(ray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rayMap;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.render;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
public interface Renderer {
|
||||||
|
|
||||||
|
BufferedImage render(Player player, Resolution resolution);
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.render;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public final class Resolution {
|
||||||
|
|
||||||
|
private final int width;
|
||||||
|
private final int height;
|
||||||
|
|
||||||
|
public Resolution(Pixels pixels, AspectRatio aspectRatio) {
|
||||||
|
Preconditions.checkNotNull(pixels);
|
||||||
|
Preconditions.checkNotNull(aspectRatio);
|
||||||
|
|
||||||
|
this.height = pixels.height;
|
||||||
|
this.width = (int) Math.round(pixels.height * aspectRatio.ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resolution(int width, int height) {
|
||||||
|
Preconditions.checkArgument(width > 0);
|
||||||
|
Preconditions.checkArgument(height > 0);
|
||||||
|
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Pixels {
|
||||||
|
_128P(128, "128p"),
|
||||||
|
_256P(256, "256p");
|
||||||
|
|
||||||
|
private final int height;
|
||||||
|
private final List<String> aliases;
|
||||||
|
|
||||||
|
Pixels(int height, String... aliases) {
|
||||||
|
this.height = height;
|
||||||
|
this.aliases = Collections.unmodifiableList(Arrays.asList(aliases));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AspectRatio {
|
||||||
|
_1_1(1, "1:1"),
|
||||||
|
_2_1(2, "2:1"),
|
||||||
|
_3_2(3 / 2.0, "3:2");
|
||||||
|
|
||||||
|
private final double ratio;
|
||||||
|
private final List<String> aliases;
|
||||||
|
|
||||||
|
AspectRatio(double ratio, String... aliases) {
|
||||||
|
this.ratio = ratio;
|
||||||
|
this.aliases = Collections.unmodifiableList(Arrays.asList(aliases));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.util;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.util.BlockIterator;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class BlockRaytracer extends BlockIterator {
|
||||||
|
|
||||||
|
private final Vector position;
|
||||||
|
private final Vector direction;
|
||||||
|
|
||||||
|
private Block lastBlock;
|
||||||
|
private BlockFace currentFace;
|
||||||
|
|
||||||
|
public BlockRaytracer(Location loc) {
|
||||||
|
super(loc);
|
||||||
|
|
||||||
|
this.position = loc.toVector();
|
||||||
|
this.direction = loc.getDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFace getIntersectionFace() {
|
||||||
|
if (currentFace == null) {
|
||||||
|
throw new IllegalStateException("Called before next()");
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getIntersectionPoint() {
|
||||||
|
BlockFace lastFace = getIntersectionFace();
|
||||||
|
Vector planeNormal = new Vector(lastFace.getModX(), lastFace.getModY(), lastFace.getModZ());
|
||||||
|
Vector planePoint = lastBlock.getLocation()
|
||||||
|
.add(0.5, 0.5, 0.5)
|
||||||
|
.toVector()
|
||||||
|
.add(planeNormal.clone().multiply(0.5));
|
||||||
|
|
||||||
|
return MathUtil.getLinePlaneIntersection(position, direction, planePoint, planeNormal, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Block next() {
|
||||||
|
Block currentBlock = super.next();
|
||||||
|
currentFace = lastBlock == null ? BlockFace.SELF : currentBlock.getFace(lastBlock);
|
||||||
|
|
||||||
|
return (lastBlock = currentBlock);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.util;
|
||||||
|
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public final class Intersection {
|
||||||
|
|
||||||
|
private final Vector normal;
|
||||||
|
private final Vector point;
|
||||||
|
private final Vector direction;
|
||||||
|
private final int color;
|
||||||
|
|
||||||
|
private Intersection(Vector normal, Vector point, Vector direction, int color) {
|
||||||
|
this.normal = normal;
|
||||||
|
this.point = point;
|
||||||
|
this.direction = direction;
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getNormal() {
|
||||||
|
return normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getPoint() {
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getDirection() {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intersection of(Vector normal, Vector point, Vector direction) {
|
||||||
|
return of(normal, point, direction, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intersection of(Vector normal, Vector point, Vector direction, int color) {
|
||||||
|
return new Intersection(normal, point, direction, color);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package eu.mhsl.minecraft.pixelpic.render.util;
|
||||||
|
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
public class MathUtil {
|
||||||
|
|
||||||
|
private MathUtil() {}
|
||||||
|
|
||||||
|
public static Vector yawPitchRotation(Vector base, double angleYaw, double anglePitch) {
|
||||||
|
double oldX = base.getX();
|
||||||
|
double oldY = base.getY();
|
||||||
|
double oldZ = base.getZ();
|
||||||
|
|
||||||
|
double sinOne = Math.sin(angleYaw);
|
||||||
|
double sinTwo = Math.sin(anglePitch);
|
||||||
|
double cosOne = Math.cos(angleYaw);
|
||||||
|
double cosTwo = Math.cos(anglePitch);
|
||||||
|
|
||||||
|
double newX = oldX * cosOne * cosTwo - oldY * cosOne * sinTwo - oldZ * sinOne;
|
||||||
|
double newY = oldX * sinTwo + oldY * cosTwo;
|
||||||
|
double newZ = oldX * sinOne * cosTwo - oldY * sinOne * sinTwo + oldZ * cosOne;
|
||||||
|
|
||||||
|
return new Vector(newX, newY, newZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector doubleYawPitchRotation(Vector base, double firstYaw, double firstPitch, double secondYaw,
|
||||||
|
double secondPitch) {
|
||||||
|
return yawPitchRotation(yawPitchRotation(base, firstYaw, firstPitch), secondYaw, secondPitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector reflectVector(Vector linePoint, Vector lineDirection, Vector planePoint, Vector planeNormal) {
|
||||||
|
return lineDirection.clone().subtract(planeNormal.clone().multiply(2 * lineDirection.dot(planeNormal)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector toVector(BlockFace face) {
|
||||||
|
return new Vector(face.getModX(), face.getModY(), face.getModZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int weightedColorSum(int rgbOne, int rgbTwo, double weightOne, double weightTwo) {
|
||||||
|
Color colorOne = Color.fromRGB(rgbOne & 0xFFFFFF);
|
||||||
|
Color colorTwo = Color.fromRGB(rgbTwo & 0xFFFFFF);
|
||||||
|
|
||||||
|
double total = weightOne + weightTwo;
|
||||||
|
int newRed = (int) ((colorOne.getRed() * weightOne + colorTwo.getRed() * weightTwo) / total);
|
||||||
|
int newGreen = (int) ((colorOne.getGreen() * weightOne + colorTwo.getGreen() * weightTwo) / total);
|
||||||
|
int newBlue = (int) ((colorOne.getBlue() * weightOne + colorTwo.getBlue() * weightTwo) / total);
|
||||||
|
|
||||||
|
return Color.fromRGB(newRed, newGreen, newBlue).asRGB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector getLinePlaneIntersection(Vector linePoint, Vector lineDirection, Vector planePoint,
|
||||||
|
Vector planeNormal, boolean allowBackwards) {
|
||||||
|
double d = planePoint.dot(planeNormal);
|
||||||
|
double t = (d - planeNormal.dot(linePoint)) / planeNormal.dot(lineDirection);
|
||||||
|
|
||||||
|
if (t < 0 && !allowBackwards) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double x = linePoint.getX() + lineDirection.getX() * t;
|
||||||
|
double y = linePoint.getY() + lineDirection.getY() * t;
|
||||||
|
double z = linePoint.getZ() + lineDirection.getZ() * t;
|
||||||
|
|
||||||
|
return new Vector(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
BIN
src/main/resources/colormap/foliage.png
Normal file
BIN
src/main/resources/colormap/foliage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
src/main/resources/colormap/grass.png
Normal file
BIN
src/main/resources/colormap/grass.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
6
src/main/resources/models/block/acacia_button.json
Normal file
6
src/main/resources/models/block/acacia_button.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/button",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/button_inventory",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/button_pressed",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_bottom_left",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_bottom_left_open",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_bottom_right",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_bottom_right_open",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_top_left",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_top_left_open",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_top_right",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/door_top_right_open",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_door_bottom",
|
||||||
|
"top": "minecraft:block/acacia_door_top"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/acacia_fence_gate.json
Normal file
6
src/main/resources/models/block/acacia_fence_gate.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_fence_gate",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_fence_gate_open",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_fence_gate_wall",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_fence_gate_wall_open",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/fence_inventory",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/acacia_fence_post.json
Normal file
6
src/main/resources/models/block/acacia_fence_post.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/fence_post",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/acacia_fence_side.json
Normal file
6
src/main/resources/models/block/acacia_fence_side.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/fence_side",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
5
src/main/resources/models/block/acacia_hanging_sign.json
Normal file
5
src/main/resources/models/block/acacia_hanging_sign.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"particle": "minecraft:block/stripped_acacia_log"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/acacia_leaves.json
Normal file
6
src/main/resources/models/block/acacia_leaves.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/leaves",
|
||||||
|
"textures": {
|
||||||
|
"all": "minecraft:block/acacia_leaves"
|
||||||
|
}
|
||||||
|
}
|
7
src/main/resources/models/block/acacia_log.json
Normal file
7
src/main/resources/models/block/acacia_log.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_column",
|
||||||
|
"textures": {
|
||||||
|
"end": "minecraft:block/acacia_log_top",
|
||||||
|
"side": "minecraft:block/acacia_log"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_column_horizontal",
|
||||||
|
"textures": {
|
||||||
|
"end": "minecraft:block/acacia_log_top",
|
||||||
|
"side": "minecraft:block/acacia_log"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/acacia_planks.json
Normal file
6
src/main/resources/models/block/acacia_planks.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_all",
|
||||||
|
"textures": {
|
||||||
|
"all": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/pressure_plate_up",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/pressure_plate_down",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/acacia_sapling.json
Normal file
6
src/main/resources/models/block/acacia_sapling.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cross",
|
||||||
|
"textures": {
|
||||||
|
"cross": "minecraft:block/acacia_sapling"
|
||||||
|
}
|
||||||
|
}
|
5
src/main/resources/models/block/acacia_sign.json
Normal file
5
src/main/resources/models/block/acacia_sign.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"particle": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/acacia_slab.json
Normal file
8
src/main/resources/models/block/acacia_slab.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/slab",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_planks",
|
||||||
|
"side": "minecraft:block/acacia_planks",
|
||||||
|
"top": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/acacia_slab_top.json
Normal file
8
src/main/resources/models/block/acacia_slab_top.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/slab_top",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_planks",
|
||||||
|
"side": "minecraft:block/acacia_planks",
|
||||||
|
"top": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/acacia_stairs.json
Normal file
8
src/main/resources/models/block/acacia_stairs.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/stairs",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_planks",
|
||||||
|
"side": "minecraft:block/acacia_planks",
|
||||||
|
"top": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/acacia_stairs_inner.json
Normal file
8
src/main/resources/models/block/acacia_stairs_inner.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/inner_stairs",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_planks",
|
||||||
|
"side": "minecraft:block/acacia_planks",
|
||||||
|
"top": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/acacia_stairs_outer.json
Normal file
8
src/main/resources/models/block/acacia_stairs_outer.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/outer_stairs",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/acacia_planks",
|
||||||
|
"side": "minecraft:block/acacia_planks",
|
||||||
|
"top": "minecraft:block/acacia_planks"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_orientable_trapdoor_bottom",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_trapdoor"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_orientable_trapdoor_open",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_trapdoor"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/acacia_trapdoor_top.json
Normal file
6
src/main/resources/models/block/acacia_trapdoor_top.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_orientable_trapdoor_top",
|
||||||
|
"textures": {
|
||||||
|
"texture": "minecraft:block/acacia_trapdoor"
|
||||||
|
}
|
||||||
|
}
|
7
src/main/resources/models/block/acacia_wood.json
Normal file
7
src/main/resources/models/block/acacia_wood.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_column",
|
||||||
|
"textures": {
|
||||||
|
"end": "minecraft:block/acacia_log",
|
||||||
|
"side": "minecraft:block/acacia_log"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/activator_rail.json
Normal file
6
src/main/resources/models/block/activator_rail.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/rail_flat",
|
||||||
|
"textures": {
|
||||||
|
"rail": "minecraft:block/activator_rail"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/activator_rail_on.json
Normal file
6
src/main/resources/models/block/activator_rail_on.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/rail_flat",
|
||||||
|
"textures": {
|
||||||
|
"rail": "minecraft:block/activator_rail_on"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_rail_raised_ne",
|
||||||
|
"textures": {
|
||||||
|
"rail": "minecraft:block/activator_rail_on"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_rail_raised_sw",
|
||||||
|
"textures": {
|
||||||
|
"rail": "minecraft:block/activator_rail_on"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_rail_raised_ne",
|
||||||
|
"textures": {
|
||||||
|
"rail": "minecraft:block/activator_rail"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_rail_raised_sw",
|
||||||
|
"textures": {
|
||||||
|
"rail": "minecraft:block/activator_rail"
|
||||||
|
}
|
||||||
|
}
|
5
src/main/resources/models/block/air.json
Normal file
5
src/main/resources/models/block/air.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"particle": "minecraft:missingno"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/allium.json
Normal file
6
src/main/resources/models/block/allium.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cross",
|
||||||
|
"textures": {
|
||||||
|
"cross": "minecraft:block/allium"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/amethyst_block.json
Normal file
6
src/main/resources/models/block/amethyst_block.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_all",
|
||||||
|
"textures": {
|
||||||
|
"all": "minecraft:block/amethyst_block"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/amethyst_cluster.json
Normal file
6
src/main/resources/models/block/amethyst_cluster.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cross",
|
||||||
|
"textures": {
|
||||||
|
"cross": "minecraft:block/amethyst_cluster"
|
||||||
|
}
|
||||||
|
}
|
7
src/main/resources/models/block/ancient_debris.json
Normal file
7
src/main/resources/models/block/ancient_debris.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_column",
|
||||||
|
"textures": {
|
||||||
|
"end": "minecraft:block/ancient_debris_top",
|
||||||
|
"side": "minecraft:block/ancient_debris_side"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/andesite.json
Normal file
6
src/main/resources/models/block/andesite.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_all",
|
||||||
|
"textures": {
|
||||||
|
"all": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/andesite_slab.json
Normal file
8
src/main/resources/models/block/andesite_slab.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/slab",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/andesite",
|
||||||
|
"side": "minecraft:block/andesite",
|
||||||
|
"top": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/andesite_slab_top.json
Normal file
8
src/main/resources/models/block/andesite_slab_top.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/slab_top",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/andesite",
|
||||||
|
"side": "minecraft:block/andesite",
|
||||||
|
"top": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
8
src/main/resources/models/block/andesite_stairs.json
Normal file
8
src/main/resources/models/block/andesite_stairs.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/stairs",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/andesite",
|
||||||
|
"side": "minecraft:block/andesite",
|
||||||
|
"top": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/inner_stairs",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/andesite",
|
||||||
|
"side": "minecraft:block/andesite",
|
||||||
|
"top": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/outer_stairs",
|
||||||
|
"textures": {
|
||||||
|
"bottom": "minecraft:block/andesite",
|
||||||
|
"side": "minecraft:block/andesite",
|
||||||
|
"top": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/wall_inventory",
|
||||||
|
"textures": {
|
||||||
|
"wall": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/andesite_wall_post.json
Normal file
6
src/main/resources/models/block/andesite_wall_post.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_wall_post",
|
||||||
|
"textures": {
|
||||||
|
"wall": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/andesite_wall_side.json
Normal file
6
src/main/resources/models/block/andesite_wall_side.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_wall_side",
|
||||||
|
"textures": {
|
||||||
|
"wall": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_wall_side_tall",
|
||||||
|
"textures": {
|
||||||
|
"wall": "minecraft:block/andesite"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/anvil.json
Normal file
6
src/main/resources/models/block/anvil.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_anvil",
|
||||||
|
"textures": {
|
||||||
|
"top": "minecraft:block/anvil_top"
|
||||||
|
}
|
||||||
|
}
|
7
src/main/resources/models/block/attached_melon_stem.json
Normal file
7
src/main/resources/models/block/attached_melon_stem.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/stem_fruit",
|
||||||
|
"textures": {
|
||||||
|
"stem": "minecraft:block/melon_stem",
|
||||||
|
"upperstem": "minecraft:block/attached_melon_stem"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/stem_fruit",
|
||||||
|
"textures": {
|
||||||
|
"stem": "minecraft:block/pumpkin_stem",
|
||||||
|
"upperstem": "minecraft:block/attached_pumpkin_stem"
|
||||||
|
}
|
||||||
|
}
|
7
src/main/resources/models/block/azalea.json
Normal file
7
src/main/resources/models/block/azalea.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/template_azalea",
|
||||||
|
"textures": {
|
||||||
|
"side": "minecraft:block/azalea_side",
|
||||||
|
"top": "minecraft:block/azalea_top"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/azalea_leaves.json
Normal file
6
src/main/resources/models/block/azalea_leaves.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_all",
|
||||||
|
"textures": {
|
||||||
|
"all": "minecraft:block/azalea_leaves"
|
||||||
|
}
|
||||||
|
}
|
6
src/main/resources/models/block/azure_bluet.json
Normal file
6
src/main/resources/models/block/azure_bluet.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cross",
|
||||||
|
"textures": {
|
||||||
|
"cross": "minecraft:block/azure_bluet"
|
||||||
|
}
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo1_age0.json
Normal file
19
src/main/resources/models/block/bamboo1_age0.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 7, 0, 7 ],
|
||||||
|
"to": [ 9, 16, 9 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 15, 6 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 15, 2], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 0, 0, 2, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 0, 0, 2, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 0, 0, 2, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 0, 0, 2, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo1_age1.json
Normal file
19
src/main/resources/models/block/bamboo1_age1.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 6.5, 0, 6.5 ],
|
||||||
|
"to": [ 9.5, 16, 9.5 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 16, 7 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 16, 3 ], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 0, 0, 3, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 0, 0, 3, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 0, 0, 3, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 0, 0, 3, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo2_age0.json
Normal file
19
src/main/resources/models/block/bamboo2_age0.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 7, 0, 7 ],
|
||||||
|
"to": [ 9, 16, 9 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 15, 6 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 15, 2], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 3, 0, 5, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 3, 0, 5, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 3, 0, 5, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 3, 0, 5, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo2_age1.json
Normal file
19
src/main/resources/models/block/bamboo2_age1.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 6.5, 0, 6.5 ],
|
||||||
|
"to": [ 9.5, 16, 9.5 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 16, 7 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 16, 3 ], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 3, 0, 6, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 3, 0, 6, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 3, 0, 6, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 3, 0, 6, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo3_age0.json
Normal file
19
src/main/resources/models/block/bamboo3_age0.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 7, 0, 7 ],
|
||||||
|
"to": [ 9, 16, 9 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 15, 6 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 15, 2], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 6, 0, 8, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 6, 0, 8, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 6, 0, 8, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 6, 0, 8, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo3_age1.json
Normal file
19
src/main/resources/models/block/bamboo3_age1.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 6.5, 0, 6.5 ],
|
||||||
|
"to": [ 9.5, 16, 9.5 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 16, 7 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 16, 3 ], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 6, 0, 9, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 6, 0, 9, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 6, 0, 9, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 6, 0, 9, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo4_age0.json
Normal file
19
src/main/resources/models/block/bamboo4_age0.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 7, 0, 7 ],
|
||||||
|
"to": [ 9, 16, 9 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 15, 6 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 15, 2], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 9, 0, 11, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 9, 0, 11, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 9, 0, 11, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 9, 0, 11, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
19
src/main/resources/models/block/bamboo4_age1.json
Normal file
19
src/main/resources/models/block/bamboo4_age1.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"textures": {
|
||||||
|
"all": "block/bamboo_stalk",
|
||||||
|
"particle": "block/bamboo_stalk"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{ "from": [ 6.5, 0, 6.5 ],
|
||||||
|
"to": [ 9.5, 16, 9.5 ],
|
||||||
|
"faces": {
|
||||||
|
"down": { "uv": [ 13, 4, 16, 7 ], "texture": "#all", "cullface": "down" },
|
||||||
|
"up": { "uv": [ 13, 0, 16, 3 ], "texture": "#all", "cullface": "up" },
|
||||||
|
"north": { "uv": [ 9, 0, 12, 16 ], "texture": "#all" },
|
||||||
|
"south": { "uv": [ 9, 0, 12, 16 ], "texture": "#all" },
|
||||||
|
"west": { "uv": [ 9, 0, 12, 16 ], "texture": "#all" },
|
||||||
|
"east": { "uv": [ 9, 0, 12, 16 ], "texture": "#all" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
7
src/main/resources/models/block/bamboo_block.json
Normal file
7
src/main/resources/models/block/bamboo_block.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_column",
|
||||||
|
"textures": {
|
||||||
|
"end": "minecraft:block/bamboo_block_top",
|
||||||
|
"side": "minecraft:block/bamboo_block"
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user