]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/commitdiff
Extract rendering logic
authorirtimaled <irtimaled@gmail.com>
Thu, 28 Dec 2017 09:17:40 +0000 (01:17 -0800)
committerirtimaled <irtimaled@gmail.com>
Sat, 30 Dec 2017 03:48:26 +0000 (19:48 -0800)
java/com/irtimaled/bbor/client/ClientBoundingBoxProvider.java
java/com/irtimaled/bbor/client/ClientProxy.java
java/com/irtimaled/bbor/client/ClientRenderer.java [new file with mode: 0644]
java/com/irtimaled/bbor/client/renderers/Renderer.java [new file with mode: 0644]
java/com/irtimaled/bbor/client/renderers/SlimeChunkRenderer.java [new file with mode: 0644]
java/com/irtimaled/bbor/client/renderers/StructureRenderer.java [new file with mode: 0644]
java/com/irtimaled/bbor/client/renderers/VillageRenderer.java [new file with mode: 0644]
java/com/irtimaled/bbor/client/renderers/WorldSpawnRenderer.java [new file with mode: 0644]

index 62d21b65e13fcb23f87d837d165cd035f35dade3..423df0906f5226f4afc5793550d103afd4b55ecc 100644 (file)
@@ -1,11 +1,13 @@
 package com.irtimaled.bbor.client;
 
+import com.irtimaled.bbor.common.BoundingBoxCache;
 import com.irtimaled.bbor.common.models.BoundingBox;
 import com.irtimaled.bbor.common.models.BoundingBoxSlimeChunk;
 import com.irtimaled.bbor.common.models.BoundingBoxWorldSpawn;
 import com.irtimaled.bbor.common.models.WorldData;
 import com.irtimaled.bbor.config.ConfigManager;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.multiplayer.WorldClient;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.ChunkPos;
 import net.minecraft.util.math.MathHelper;
@@ -15,6 +17,7 @@ import java.awt.*;
 import java.util.HashSet;
 import java.util.Random;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 class ClientBoundingBoxProvider {
     private final ClientDimensionCache dimensionCache;
@@ -23,15 +26,29 @@ class ClientBoundingBoxProvider {
         this.dimensionCache = dimensionCache;
     }
 
-    Set<BoundingBox> getClientBoundingBoxes(DimensionType dimensionType) {
-        WorldData worldData = dimensionCache.getWorldData();
-
-        if (worldData == null) {
-            return null;
+    Set<BoundingBox> getBoundingBoxes(DimensionType dimensionType, Boolean outerBoxOnly, WorldClient world) {
+        Set<BoundingBox> boundingBoxes = getClientBoundingBoxes(dimensionType);
+        BoundingBoxCache boundingBoxCache = dimensionCache.getBoundingBoxes(dimensionType);
+        if (boundingBoxCache != null) {
+            if (outerBoxOnly) {
+                boundingBoxes.addAll(boundingBoxCache.getBoundingBoxes().keySet());
+            } else {
+                boundingBoxCache.getBoundingBoxes()
+                        .values()
+                        .forEach(boundingBoxes::addAll);
+            }
         }
 
+        return boundingBoxes.stream()
+                .filter(bb -> world.isAreaLoaded(bb.getMinBlockPos(), bb.getMaxBlockPos()))
+                .collect(Collectors.toSet());
+    }
+
+    private Set<BoundingBox> getClientBoundingBoxes(DimensionType dimensionType) {
+        WorldData worldData = dimensionCache.getWorldData();
+
         Set<BoundingBox> boundingBoxes = new HashSet<>();
-        if (dimensionType == DimensionType.OVERWORLD) {
+        if (worldData != null && dimensionType == DimensionType.OVERWORLD) {
             if (ConfigManager.drawWorldSpawn.getBoolean()) {
                 boundingBoxes.add(getWorldSpawnBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
                 boundingBoxes.add(buildSpawnChunksBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
index 6d62f33b68ddc01ee7b9a79184a4babef83e676b..430a36d80aba19f5d8a53745c7e566df8cbe5001 100644 (file)
@@ -1,39 +1,26 @@
 package com.irtimaled.bbor.client;
 
-import com.irtimaled.bbor.common.BoundingBoxCache;
 import com.irtimaled.bbor.common.CommonProxy;
 import com.irtimaled.bbor.common.VillageColorCache;
 import com.irtimaled.bbor.common.VillageProcessor;
-import com.irtimaled.bbor.common.models.*;
 import com.irtimaled.bbor.config.ConfigManager;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.multiplayer.WorldClient;
-import net.minecraft.client.renderer.BufferBuilder;
-import net.minecraft.client.renderer.Tessellator;
-import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
 import net.minecraft.client.settings.KeyBinding;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.network.NetworkManager;
-import net.minecraft.util.math.AxisAlignedBB;
-import net.minecraft.util.math.BlockPos;
 import net.minecraft.world.DimensionType;
 import org.apache.commons.lang3.ArrayUtils;
 import org.lwjgl.input.Keyboard;
-import org.lwjgl.opengl.GL11;
 
-import java.awt.*;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
 
 public class ClientProxy extends CommonProxy {
     private boolean active;
     private boolean outerBoxOnly;
     private KeyBinding activeHotKey;
     private KeyBinding outerBoxOnlyHotKey;
-    private ClientBoundingBoxProvider clientBoundingBoxProvider;
+    private ClientRenderer renderer;
 
     public void keyPressed() {
         if (activeHotKey.isPressed()) {
@@ -52,7 +39,7 @@ public class ClientProxy extends CommonProxy {
         outerBoxOnlyHotKey = new KeyBinding("Toggle Display Outer Box Only", Keyboard.KEY_O, category);
         Minecraft.getMinecraft().gameSettings.keyBindings = ArrayUtils.addAll(Minecraft.getMinecraft().gameSettings.keyBindings, activeHotKey, outerBoxOnlyHotKey);
         ClientDimensionCache clientDimensionCache = new ClientDimensionCache();
-        clientBoundingBoxProvider = new ClientBoundingBoxProvider(clientDimensionCache);
+        renderer = new ClientRenderer(clientDimensionCache);
         dimensionCache = clientDimensionCache;
     }
 
@@ -61,13 +48,7 @@ public class ClientProxy extends CommonProxy {
         PlayerData.setPlayerPosition(partialTicks, entityPlayer);
 
         if (this.active) {
-            DimensionType dimensionType = DimensionType.getById(entityPlayer.dimension);
-            Map<BoundingBox, Set<BoundingBox>> boundingBoxes = null;
-            BoundingBoxCache boundingBoxCache = dimensionCache.getBoundingBoxes(dimensionType);
-            if (boundingBoxCache != null) {
-                boundingBoxes = boundingBoxCache.getBoundingBoxes();
-            }
-            renderBoundingBoxes(boundingBoxes, clientBoundingBoxProvider.getClientBoundingBoxes(dimensionType));
+            renderer.render(DimensionType.getById(entityPlayer.dimension), outerBoxOnly);
         }
     }
 
@@ -86,337 +67,4 @@ public class ClientProxy extends CommonProxy {
         dimensionCache.clear();
         villageProcessors.forEach(VillageProcessor::clear);
     }
-
-    private void renderBoundingBoxes(Map<BoundingBox, Set<BoundingBox>> map, Set<BoundingBox> clientBoundingBoxes) {
-        if (map == null && clientBoundingBoxes == null)
-            return;
-
-        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
-        GL11.glLineWidth(2.0f);
-        GL11.glDisable(GL11.GL_TEXTURE_2D);
-        GL11.glDisable(GL11.GL_CULL_FACE);
-
-        if (ConfigManager.alwaysVisible.getBoolean()) {
-            GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
-        }
-
-        if (map != null)
-            for (BoundingBox bb : map.keySet()) {
-                if (outerBoxOnly) {
-                    renderBoundingBoxSet(map.get(bb));
-                } else {
-                    renderBoundingBoxByType(bb);
-                }
-            }
-
-        if (clientBoundingBoxes != null)
-            renderBoundingBoxSet(clientBoundingBoxes);
-
-        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
-        GL11.glEnable(GL11.GL_CULL_FACE);
-        GL11.glEnable(GL11.GL_TEXTURE_2D);
-    }
-
-    private void renderBoundingBoxSet(Set<BoundingBox> bbList) {
-        if (bbList != null)
-            for (BoundingBox bb : bbList) {
-                renderBoundingBoxByType(bb);
-            }
-    }
-
-    private void renderBoundingBoxByType(BoundingBox bb) {
-        WorldClient world = Minecraft.getMinecraft().world;
-        if (!world.isAreaLoaded(bb.getMinBlockPos(), bb.getMaxBlockPos())) {
-            return;
-        }
-
-        if (bb instanceof BoundingBoxVillage) {
-            BoundingBoxVillage villageBB = (BoundingBoxVillage) bb;
-            if (ConfigManager.renderVillageAsSphere.getBoolean()) {
-                renderBoundingBoxVillageAsSphere(villageBB);
-            } else {
-                renderBoundingBox(villageBB);
-            }
-            if (ConfigManager.drawIronGolemSpawnArea.getBoolean() &&
-                    villageBB.getSpawnsIronGolems()) {
-                renderIronGolemSpawnArea(villageBB);
-            }
-            if (ConfigManager.drawVillageDoors.getBoolean())
-                renderVillageDoors(villageBB);
-        } else if (bb instanceof BoundingBoxSlimeChunk) {
-            renderSlimeChunk((BoundingBoxSlimeChunk) bb);
-        } else if (bb instanceof BoundingBoxWorldSpawn) {
-            renderWorldSpawn((BoundingBoxWorldSpawn) bb);
-        } else {
-            renderBoundingBox(bb);
-        }
-    }
-
-    private void renderBoundingBox(BoundingBox bb) {
-        AxisAlignedBB aaBB = bb.toAxisAlignedBB();
-        Color color = bb.getColor();
-        renderCuboid(aaBB, color, fill());
-    }
-
-    private void renderWorldSpawn(BoundingBoxWorldSpawn bb) {
-        AxisAlignedBB aaBB = bb.toAxisAlignedBB(false);
-        Color color = bb.getColor();
-        double y = PlayerData.getMaxY(ConfigManager.worldSpawnMaxY.getInt()) + 0.001F;
-        renderRectangle(aaBB, y, y, color, false);
-    }
-
-    private void renderSlimeChunk(BoundingBoxSlimeChunk bb) {
-        AxisAlignedBB aaBB = bb.toAxisAlignedBB();
-        Color color = bb.getColor();
-        renderCuboid(aaBB, color, fill());
-
-        double maxY = PlayerData.getMaxY(ConfigManager.slimeChunkMaxY.getInt());
-        if (maxY > 39) {
-            renderRectangle(aaBB, 39, maxY, color, fill());
-        }
-    }
-
-    private void renderRectangle(AxisAlignedBB aaBB, double minY, double maxY, Color color, Boolean fill) {
-        aaBB = new AxisAlignedBB(aaBB.minX, minY, aaBB.minZ, aaBB.maxX, maxY, aaBB.maxZ);
-        renderCuboid(aaBB, color, fill);
-    }
-
-    private boolean fill() {
-        return ConfigManager.fill.getBoolean();
-    }
-
-    private void renderIronGolemSpawnArea(BoundingBoxVillage villageBB) {
-        BlockPos center = villageBB.getCenter();
-        AxisAlignedBB abb = new AxisAlignedBB(new BlockPos(center.getX() - 8,
-                center.getY() - 3,
-                center.getZ() - 8),
-                new BlockPos(center.getX() + 8,
-                        center.getY() + 3,
-                        center.getZ() + 8))
-                .offset(villageBB.getCenterOffsetX(), 0.0, villageBB.getCenterOffsetZ());
-
-        renderCuboid(abb, villageBB.getColor(), false);
-    }
-
-    private void renderVillageDoors(BoundingBoxVillage villageBB) {
-        OffsetPoint center = new OffsetPoint(villageBB.getCenter())
-                .add(villageBB.getCenterOffsetX(), 0.0, villageBB.getCenterOffsetZ());
-        Color color = villageBB.getColor();
-        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
-        Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder worldRenderer = tessellator.getBuffer();
-
-        int colorR = color.getRed();
-        int colorG = color.getGreen();
-        int colorB = color.getBlue();
-
-        worldRenderer.begin(GL11.GL_LINES, worldRenderer.getVertexFormat());
-        for (BlockPos door : villageBB.getDoors()) {
-            OffsetPoint point = new OffsetPoint(door).add(0.5, 0, 0.5);
-
-            worldRenderer.pos(point.getX(), point.getY(), point.getZ()).color(colorR, colorG, colorB, 255).endVertex();
-            worldRenderer.pos(center.getX(), center.getY(), center.getZ()).color(colorR, colorG, colorB, 255).endVertex();
-        }
-        tessellator.draw();
-    }
-
-    private void renderCuboid(AxisAlignedBB aaBB, Color color, boolean fill) {
-        aaBB = offsetAxisAlignedBB(aaBB);
-        if (fill) {
-            renderFilledCuboid(aaBB, color);
-        }
-        renderUnfilledCuboid(aaBB, color);
-    }
-
-    private void renderFilledCuboid(AxisAlignedBB aaBB, Color color) {
-        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
-        GL11.glEnable(GL11.GL_BLEND);
-        renderCuboid(aaBB, 30, color);
-        GL11.glDisable(GL11.GL_BLEND);
-        GL11.glEnable(GL11.GL_POLYGON_OFFSET_LINE);
-        GL11.glPolygonOffset(-1.f, -1.f);
-    }
-
-    private void renderUnfilledCuboid(AxisAlignedBB aaBB, Color color) {
-        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
-        renderCuboid(aaBB, 255, color);
-    }
-
-    private void renderCuboid(AxisAlignedBB bb, int alphaChannel, Color color) {
-        Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder worldRenderer = tessellator.getBuffer();
-
-        int colorR = color.getRed();
-        int colorG = color.getGreen();
-        int colorB = color.getBlue();
-
-        worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
-        worldRenderer.pos(bb.minX, bb.minY, bb.minZ)
-                .color(colorR, colorG, colorB, alphaChannel)
-                .endVertex();
-        worldRenderer.pos(bb.maxX, bb.minY, bb.minZ)
-                .color(colorR, colorG, colorB, alphaChannel)
-                .endVertex();
-        worldRenderer.pos(bb.maxX, bb.minY, bb.maxZ)
-                .color(colorR, colorG, colorB, alphaChannel)
-                .endVertex();
-        worldRenderer.pos(bb.minX, bb.minY, bb.maxZ)
-                .color(colorR, colorG, colorB, alphaChannel)
-                .endVertex();
-
-        if (bb.minY != bb.maxY) {
-            worldRenderer.pos(bb.minX, bb.maxY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.maxY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.maxY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.minX, bb.maxY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-
-            worldRenderer.pos(bb.minX, bb.minY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.minX, bb.maxY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.maxY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.minY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-
-            worldRenderer.pos(bb.minX, bb.minY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.minX, bb.maxY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.maxY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.minY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-
-            worldRenderer.pos(bb.minX, bb.minY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.minX, bb.minY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.minX, bb.maxY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.minX, bb.maxY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-
-            worldRenderer.pos(bb.maxX, bb.minY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.minY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.maxY, bb.maxZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-            worldRenderer.pos(bb.maxX, bb.maxY, bb.minZ)
-                    .color(colorR, colorG, colorB, alphaChannel)
-                    .endVertex();
-        }
-        tessellator.draw();
-    }
-
-    private AxisAlignedBB offsetAxisAlignedBB(AxisAlignedBB axisAlignedBB) {
-        double growXZ = 0.001F;
-        double growY = 0;
-        if (axisAlignedBB.minY != axisAlignedBB.maxY) {
-            growY = growXZ;
-        }
-        return axisAlignedBB
-                .grow(growXZ, growY, growXZ)
-                .offset(-PlayerData.getX(), -PlayerData.getY(), -PlayerData.getZ());
-    }
-
-    private void renderBoundingBoxVillageAsSphere(BoundingBoxVillage bb) {
-        OffsetPoint center = new OffsetPoint(bb.getCenter())
-                .add(bb.getCenterOffsetX(), 0.0, bb.getCenterOffsetZ());
-        ;
-        int radius = bb.getRadius();
-        Color color = bb.getColor();
-        renderSphere(center, radius, color);
-    }
-
-    private void renderSphere(OffsetPoint center, double radius, Color color) {
-        GL11.glEnable(GL11.GL_POINT_SMOOTH);
-        GL11.glPointSize(2f);
-
-        Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder worldRenderer = tessellator.getBuffer();
-        worldRenderer.begin(GL11.GL_POINTS, DefaultVertexFormats.POSITION_COLOR);
-        for (OffsetPoint point : buildPoints(center, radius)) {
-            worldRenderer.pos(point.getX(), point.getY(), point.getZ())
-                    .color(color.getRed(), color.getGreen(), color.getBlue(), 255)
-                    .endVertex();
-        }
-        tessellator.draw();
-    }
-
-    private class OffsetPoint {
-        private final double x;
-        private final double y;
-        private final double z;
-
-        public OffsetPoint(double x, double y, double z) {
-            this.x = x;
-            this.y = y;
-            this.z = z;
-        }
-
-        public OffsetPoint(BlockPos blockPos) {
-            x = blockPos.getX();
-            y = blockPos.getY();
-            z = blockPos.getZ();
-        }
-
-        public double getX() {
-            return x - PlayerData.getX();
-        }
-
-        public double getY() {
-            return y - PlayerData.getY();
-        }
-
-        public double getZ() {
-            return z - PlayerData.getZ();
-        }
-
-        public OffsetPoint add(double x, double y, double z) {
-            return new OffsetPoint(this.x + x, this.y + y, this.z + z);
-        }
-    }
-
-    private Set<OffsetPoint> buildPoints(OffsetPoint center, double radius) {
-        Set<OffsetPoint> points = new HashSet<>(1200);
-
-        double tau = 6.283185307179586D;
-        double pi = tau / 2D;
-        double segment = tau / 48D;
-
-        for (double t = 0.0D; t < tau; t += segment)
-            for (double theta = 0.0D; theta < pi; theta += segment) {
-                double dx = radius * Math.sin(t) * Math.cos(theta);
-                double dz = radius * Math.sin(t) * Math.sin(theta);
-                double dy = radius * Math.cos(t);
-
-                points.add(center.add(dx, dy, dz));
-            }
-        return points;
-    }
 }
diff --git a/java/com/irtimaled/bbor/client/ClientRenderer.java b/java/com/irtimaled/bbor/client/ClientRenderer.java
new file mode 100644 (file)
index 0000000..697c26b
--- /dev/null
@@ -0,0 +1,50 @@
+package com.irtimaled.bbor.client;
+
+import com.irtimaled.bbor.client.renderers.*;
+import com.irtimaled.bbor.common.models.*;
+import com.irtimaled.bbor.config.ConfigManager;
+import net.minecraft.client.Minecraft;
+import net.minecraft.world.DimensionType;
+import org.lwjgl.opengl.GL11;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class ClientRenderer {
+    private final ClientBoundingBoxProvider clientBoundingBoxProvider;
+    private static final Map<Class<? extends BoundingBox>, Renderer> boundingBoxRendererMap = new HashMap<>();
+
+    ClientRenderer(ClientDimensionCache dimensionCache) {
+        this.clientBoundingBoxProvider = new ClientBoundingBoxProvider(dimensionCache);
+        boundingBoxRendererMap.put(BoundingBoxVillage.class, new VillageRenderer());
+        boundingBoxRendererMap.put(BoundingBoxSlimeChunk.class, new SlimeChunkRenderer());
+        boundingBoxRendererMap.put(BoundingBoxWorldSpawn.class, new WorldSpawnRenderer());
+        boundingBoxRendererMap.put(BoundingBoxStructure.class, new StructureRenderer());
+    }
+
+    public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
+        Set<BoundingBox> boundingBoxes = clientBoundingBoxProvider.getBoundingBoxes(dimensionType, outerBoxesOnly, Minecraft.getMinecraft().world);
+        if (boundingBoxes == null || boundingBoxes.size() == 0)
+            return;
+
+        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+        GL11.glLineWidth(2.0f);
+        GL11.glDisable(GL11.GL_TEXTURE_2D);
+        GL11.glDisable(GL11.GL_CULL_FACE);
+
+        if (ConfigManager.alwaysVisible.getBoolean()) {
+            GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
+        }
+        for (BoundingBox bb : boundingBoxes) {
+            Renderer renderer = boundingBoxRendererMap.get(bb.getClass());
+            if (renderer != null) {
+                renderer.render(bb);
+            }
+        }
+
+        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
+        GL11.glEnable(GL11.GL_CULL_FACE);
+        GL11.glEnable(GL11.GL_TEXTURE_2D);
+    }
+}
diff --git a/java/com/irtimaled/bbor/client/renderers/Renderer.java b/java/com/irtimaled/bbor/client/renderers/Renderer.java
new file mode 100644 (file)
index 0000000..850c800
--- /dev/null
@@ -0,0 +1,154 @@
+package com.irtimaled.bbor.client.renderers;
+
+import com.irtimaled.bbor.client.PlayerData;
+import com.irtimaled.bbor.common.models.BoundingBox;
+import com.irtimaled.bbor.config.ConfigManager;
+import net.minecraft.client.renderer.BufferBuilder;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.util.math.AxisAlignedBB;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+
+public abstract class Renderer<T extends BoundingBox> {
+    public abstract void render(T boundingBox);
+
+    void renderBoundingBox(T boundingBox) {
+        renderCuboid(boundingBox.toAxisAlignedBB(), boundingBox.getColor(), fill());
+    }
+
+    boolean fill() {
+        return ConfigManager.fill.getBoolean();
+    }
+
+    void renderRectangle(AxisAlignedBB aaBB, double minY, double maxY, Color color, Boolean fill) {
+        aaBB = new AxisAlignedBB(aaBB.minX, minY, aaBB.minZ, aaBB.maxX, maxY, aaBB.maxZ);
+        renderCuboid(aaBB, color, fill);
+    }
+
+    void renderCuboid(AxisAlignedBB aaBB, Color color, boolean fill) {
+        aaBB = offsetAxisAlignedBB(aaBB);
+        if (fill) {
+            renderFilledCuboid(aaBB, color);
+        }
+        renderUnfilledCuboid(aaBB, color);
+    }
+
+    private AxisAlignedBB offsetAxisAlignedBB(AxisAlignedBB axisAlignedBB) {
+        double growXZ = 0.001F;
+        double growY = 0;
+        if (axisAlignedBB.minY != axisAlignedBB.maxY) {
+            growY = growXZ;
+        }
+        return axisAlignedBB
+                .grow(growXZ, growY, growXZ)
+                .offset(-PlayerData.getX(), -PlayerData.getY(), -PlayerData.getZ());
+    }
+
+    private void renderFilledCuboid(AxisAlignedBB aaBB, Color color) {
+        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
+        GL11.glEnable(GL11.GL_BLEND);
+        renderCuboid(aaBB, 30, color);
+        GL11.glDisable(GL11.GL_BLEND);
+        GL11.glEnable(GL11.GL_POLYGON_OFFSET_LINE);
+        GL11.glPolygonOffset(-1.f, -1.f);
+    }
+
+    private void renderUnfilledCuboid(AxisAlignedBB aaBB, Color color) {
+        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
+        renderCuboid(aaBB, 255, color);
+    }
+
+    private void renderCuboid(AxisAlignedBB bb, int alphaChannel, Color color) {
+        Tessellator tessellator = Tessellator.getInstance();
+        BufferBuilder worldRenderer = tessellator.getBuffer();
+
+        int colorR = color.getRed();
+        int colorG = color.getGreen();
+        int colorB = color.getBlue();
+
+        worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
+        worldRenderer.pos(bb.minX, bb.minY, bb.minZ)
+                .color(colorR, colorG, colorB, alphaChannel)
+                .endVertex();
+        worldRenderer.pos(bb.maxX, bb.minY, bb.minZ)
+                .color(colorR, colorG, colorB, alphaChannel)
+                .endVertex();
+        worldRenderer.pos(bb.maxX, bb.minY, bb.maxZ)
+                .color(colorR, colorG, colorB, alphaChannel)
+                .endVertex();
+        worldRenderer.pos(bb.minX, bb.minY, bb.maxZ)
+                .color(colorR, colorG, colorB, alphaChannel)
+                .endVertex();
+
+        if (bb.minY != bb.maxY) {
+
+            worldRenderer.pos(bb.minX, bb.maxY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.maxY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.maxY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.minX, bb.maxY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+
+            worldRenderer.pos(bb.minX, bb.minY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.minX, bb.maxY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.maxY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.minY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+
+            worldRenderer.pos(bb.minX, bb.minY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.minX, bb.maxY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.maxY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.minY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+
+            worldRenderer.pos(bb.minX, bb.minY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.minX, bb.minY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.minX, bb.maxY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.minX, bb.maxY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+
+            worldRenderer.pos(bb.maxX, bb.minY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.minY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.maxY, bb.maxZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+            worldRenderer.pos(bb.maxX, bb.maxY, bb.minZ)
+                    .color(colorR, colorG, colorB, alphaChannel)
+                    .endVertex();
+        }
+        tessellator.draw();
+    }
+}
diff --git a/java/com/irtimaled/bbor/client/renderers/SlimeChunkRenderer.java b/java/com/irtimaled/bbor/client/renderers/SlimeChunkRenderer.java
new file mode 100644 (file)
index 0000000..1ba3765
--- /dev/null
@@ -0,0 +1,22 @@
+package com.irtimaled.bbor.client.renderers;
+
+import com.irtimaled.bbor.common.models.BoundingBoxSlimeChunk;
+import com.irtimaled.bbor.client.PlayerData;
+import com.irtimaled.bbor.config.ConfigManager;
+import net.minecraft.util.math.AxisAlignedBB;
+
+import java.awt.*;
+
+public class SlimeChunkRenderer extends Renderer<BoundingBoxSlimeChunk> {
+    @Override
+    public void render(BoundingBoxSlimeChunk boundingBox) {
+        AxisAlignedBB aaBB = boundingBox.toAxisAlignedBB();
+        Color color = boundingBox.getColor();
+        renderCuboid(aaBB, color, fill());
+
+        double maxY = PlayerData.getMaxY(ConfigManager.slimeChunkMaxY.getInt());
+        if (maxY > 39) {
+            renderRectangle(aaBB, 39, maxY, color, fill());
+        }
+    }
+}
diff --git a/java/com/irtimaled/bbor/client/renderers/StructureRenderer.java b/java/com/irtimaled/bbor/client/renderers/StructureRenderer.java
new file mode 100644 (file)
index 0000000..e98cec8
--- /dev/null
@@ -0,0 +1,10 @@
+package com.irtimaled.bbor.client.renderers;
+
+import com.irtimaled.bbor.common.models.BoundingBoxStructure;
+
+public class StructureRenderer extends Renderer<BoundingBoxStructure> {
+    @Override
+    public void render(BoundingBoxStructure boundingBox) {
+        renderBoundingBox(boundingBox);
+    }
+}
diff --git a/java/com/irtimaled/bbor/client/renderers/VillageRenderer.java b/java/com/irtimaled/bbor/client/renderers/VillageRenderer.java
new file mode 100644 (file)
index 0000000..d5bee1f
--- /dev/null
@@ -0,0 +1,143 @@
+package com.irtimaled.bbor.client.renderers;
+
+import com.irtimaled.bbor.common.models.BoundingBoxVillage;
+import com.irtimaled.bbor.client.PlayerData;
+import com.irtimaled.bbor.config.ConfigManager;
+import net.minecraft.client.renderer.BufferBuilder;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.util.math.AxisAlignedBB;
+import net.minecraft.util.math.BlockPos;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+
+public class VillageRenderer extends Renderer<BoundingBoxVillage> {
+    @Override
+    public void render(BoundingBoxVillage boundingBox) {
+        if (ConfigManager.renderVillageAsSphere.getBoolean()) {
+            renderBoundingBoxVillageAsSphere(boundingBox);
+        } else {
+            renderBoundingBox(boundingBox);
+        }
+        if (ConfigManager.drawIronGolemSpawnArea.getBoolean() &&
+                boundingBox.getSpawnsIronGolems()) {
+            renderIronGolemSpawnArea(boundingBox);
+        }
+        if (ConfigManager.drawVillageDoors.getBoolean()) {
+            renderVillageDoors(boundingBox);
+        }
+    }
+
+    private void renderIronGolemSpawnArea(BoundingBoxVillage boundingBox) {
+        BlockPos center = boundingBox.getCenter();
+        AxisAlignedBB abb = new AxisAlignedBB(new BlockPos(center.getX() - 8,
+                center.getY() - 3,
+                center.getZ() - 8),
+                new BlockPos(center.getX() + 8,
+                        center.getY() + 3,
+                        center.getZ() + 8))
+                .offset(boundingBox.getCenterOffsetX(), 0.0, boundingBox.getCenterOffsetZ());
+
+        renderCuboid(abb, boundingBox.getColor(), false);
+    }
+
+    private void renderVillageDoors(BoundingBoxVillage boundingBox) {
+        OffsetPoint center = new OffsetPoint(boundingBox.getCenter())
+                .add(boundingBox.getCenterOffsetX(), 0.0, boundingBox.getCenterOffsetZ());
+        Color color = boundingBox.getColor();
+        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
+        Tessellator tessellator = Tessellator.getInstance();
+        BufferBuilder worldRenderer = tessellator.getBuffer();
+
+        int colorR = color.getRed();
+        int colorG = color.getGreen();
+        int colorB = color.getBlue();
+
+        worldRenderer.begin(GL11.GL_LINES, worldRenderer.getVertexFormat());
+        for (BlockPos door : boundingBox.getDoors()) {
+            OffsetPoint point = new OffsetPoint(door).add(0.5, 0, 0.5);
+
+            worldRenderer.pos(point.getX(), point.getY(), point.getZ()).color(colorR, colorG, colorB, 255).endVertex();
+            worldRenderer.pos(center.getX(), center.getY(), center.getZ()).color(colorR, colorG, colorB, 255).endVertex();
+        }
+        tessellator.draw();
+    }
+
+    private void renderBoundingBoxVillageAsSphere(BoundingBoxVillage boundingBox) {
+        OffsetPoint center = new OffsetPoint(boundingBox.getCenter())
+                .add(boundingBox.getCenterOffsetX(), 0.0, boundingBox.getCenterOffsetZ());
+        int radius = boundingBox.getRadius();
+        Color color = boundingBox.getColor();
+        renderSphere(center, radius, color);
+    }
+
+    private void renderSphere(OffsetPoint center, double radius, Color color) {
+        GL11.glEnable(GL11.GL_POINT_SMOOTH);
+        GL11.glPointSize(2f);
+
+        Tessellator tessellator = Tessellator.getInstance();
+        BufferBuilder worldRenderer = tessellator.getBuffer();
+        worldRenderer.begin(GL11.GL_POINTS, DefaultVertexFormats.POSITION_COLOR);
+        for (OffsetPoint point : buildPoints(center, radius)) {
+            worldRenderer.pos(point.getX(), point.getY(), point.getZ())
+                    .color(color.getRed(), color.getGreen(), color.getBlue(), 255)
+                    .endVertex();
+        }
+        tessellator.draw();
+    }
+
+    private class OffsetPoint {
+        private final double x;
+        private final double y;
+        private final double z;
+
+        OffsetPoint(double x, double y, double z) {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        }
+
+        OffsetPoint(BlockPos blockPos) {
+            this.x = blockPos.getX();
+            this.y = blockPos.getY();
+            this.z = blockPos.getZ();
+        }
+
+        double getX() {
+            return x - PlayerData.getX();
+        }
+
+        double getY() {
+            return y - PlayerData.getY();
+        }
+
+        double getZ() {
+            return z - PlayerData.getZ();
+        }
+
+        public OffsetPoint add(double x, double y, double z) {
+            return new OffsetPoint(this.x + x, this.y + y, this.z + z);
+        }
+    }
+
+    private Set<OffsetPoint> buildPoints(OffsetPoint center, double radius) {
+        Set<OffsetPoint> points = new HashSet<>(1200);
+
+        double tau = 6.283185307179586D;
+        double pi = tau / 2D;
+        double segment = tau / 48D;
+
+        for (double t = 0.0D; t < tau; t += segment)
+            for (double theta = 0.0D; theta < pi; theta += segment) {
+                double dx = radius * Math.sin(t) * Math.cos(theta);
+                double dz = radius * Math.sin(t) * Math.sin(theta);
+                double dy = radius * Math.cos(t);
+
+                points.add(center.add(dx, dy, dz));
+            }
+        return points;
+    }
+}
diff --git a/java/com/irtimaled/bbor/client/renderers/WorldSpawnRenderer.java b/java/com/irtimaled/bbor/client/renderers/WorldSpawnRenderer.java
new file mode 100644 (file)
index 0000000..98ac02d
--- /dev/null
@@ -0,0 +1,18 @@
+package com.irtimaled.bbor.client.renderers;
+
+import com.irtimaled.bbor.common.models.BoundingBoxWorldSpawn;
+import com.irtimaled.bbor.client.PlayerData;
+import com.irtimaled.bbor.config.ConfigManager;
+import net.minecraft.util.math.AxisAlignedBB;
+
+import java.awt.*;
+
+public class WorldSpawnRenderer extends Renderer<BoundingBoxWorldSpawn> {
+    @Override
+    public void render(BoundingBoxWorldSpawn boundingBox) {
+        AxisAlignedBB aaBB = boundingBox.toAxisAlignedBB(false);
+        Color color = boundingBox.getColor();
+        double y = PlayerData.getMaxY(ConfigManager.worldSpawnMaxY.getInt()) + 0.001F;
+        renderRectangle(aaBB, y, y, color, false);
+    }
+}
\ No newline at end of file