]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/client/ClientRenderer.java
a828369d57826b0efab76a66181add6610c9300e
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / client / ClientRenderer.java
1 package com.irtimaled.bbor.client;
2
3 import com.irtimaled.bbor.client.renderers.*;
4 import com.irtimaled.bbor.common.BoundingBoxCache;
5 import com.irtimaled.bbor.common.BoundingBoxType;
6 import com.irtimaled.bbor.common.Dimensions;
7 import com.irtimaled.bbor.common.MathHelper;
8 import com.irtimaled.bbor.common.models.*;
9 import com.irtimaled.bbor.config.ConfigManager;
10 import net.minecraft.client.Minecraft;
11 import org.lwjgl.opengl.GL11;
12
13 import java.util.*;
14
15 public class ClientRenderer {
16     private static final int CHUNK_SIZE = 16;
17     private static final Map<Class<? extends BoundingBox>, Renderer> boundingBoxRendererMap = new HashMap<>();
18
19     private final GetCache getCache;
20     private long seed;
21     private Set<BoundingBox> spawnChunkBoundingBoxes = new HashSet<>();
22
23     ClientRenderer(GetCache getCache) {
24         this.getCache = getCache;
25         boundingBoxRendererMap.put(BoundingBoxVillage.class, new VillageRenderer());
26         boundingBoxRendererMap.put(BoundingBoxSlimeChunk.class, new SlimeChunkRenderer());
27         boundingBoxRendererMap.put(BoundingBoxWorldSpawn.class, new WorldSpawnRenderer());
28         boundingBoxRendererMap.put(BoundingBoxStructure.class, new StructureRenderer());
29         boundingBoxRendererMap.put(BoundingBoxMobSpawner.class, new MobSpawnerRenderer());
30     }
31
32     private boolean isWithinRenderDistance(BoundingBox boundingBox) {
33         Coords minCoords = boundingBox.getMinCoords();
34         Coords maxCoords = boundingBox.getMaxCoords();
35         int renderDistanceBlocks = getRenderDistanceChunks() * CHUNK_SIZE;
36         int minX = MathHelper.floor(PlayerCoords.getX() - renderDistanceBlocks);
37         int maxX = MathHelper.floor(PlayerCoords.getX() + renderDistanceBlocks);
38         int minZ = MathHelper.floor(PlayerCoords.getZ() - renderDistanceBlocks);
39         int maxZ = MathHelper.floor(PlayerCoords.getZ() + renderDistanceBlocks);
40
41         return maxCoords.getX() >= minX &&
42                 maxCoords.getZ() >= minZ &&
43                 minCoords.getX() <= maxX &&
44                 minCoords.getZ() <= maxZ;
45     }
46
47     public void render(int dimensionId, Boolean outerBoxesOnly) {
48         Map<BoundingBox, Set<BoundingBox>> boundingBoxes = getBoundingBoxes(dimensionId);
49
50         GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
51         GL11.glLineWidth(2.0f);
52         GL11.glDisable(GL11.GL_TEXTURE_2D);
53         GL11.glDisable(GL11.GL_CULL_FACE);
54
55         if (ConfigManager.alwaysVisible.get()) {
56             GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
57         }
58         for (Map.Entry<BoundingBox, Set<BoundingBox>> entry : boundingBoxes.entrySet()) {
59             BoundingBox key = entry.getKey();
60             if (!key.shouldRender()) continue;
61
62             Renderer renderer = boundingBoxRendererMap.get(key.getClass());
63             if (renderer == null) continue;
64
65             if (!outerBoxesOnly) {
66                 Set<BoundingBox> children = entry.getValue();
67                 if (children != null) {
68                     children.forEach(renderer::render);
69                     continue;
70                 }
71             }
72             renderer.render(key);
73         }
74
75         GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
76         GL11.glEnable(GL11.GL_CULL_FACE);
77         GL11.glEnable(GL11.GL_TEXTURE_2D);
78     }
79
80     private Map<BoundingBox, Set<BoundingBox>> getBoundingBoxes(int dimensionId) {
81         Map<BoundingBox, Set<BoundingBox>> boundingBoxes = new HashMap<>();
82         if (dimensionId == Dimensions.OVERWORLD) {
83             if (BoundingBoxType.SlimeChunks.shouldRender()) {
84                 addSlimeChunks(boundingBoxes);
85             }
86
87             for (BoundingBox boundingBox : spawnChunkBoundingBoxes) {
88                 if (boundingBox.shouldRender() && isWithinRenderDistance(boundingBox)) {
89                     boundingBoxes.put(boundingBox, null);
90                 }
91             }
92         }
93
94         BoundingBoxCache cache = getCache.apply(dimensionId);
95         if (cache != null) {
96             for (Map.Entry<BoundingBox, Set<BoundingBox>> entry : cache.getBoundingBoxes().entrySet()) {
97                 BoundingBox key = entry.getKey();
98                 if (key.shouldRender() && isWithinRenderDistance(key)) {
99                     boundingBoxes.put(key, entry.getValue());
100                 }
101             }
102         }
103         return boundingBoxes;
104     }
105
106     private void addSlimeChunks(Map<BoundingBox, Set<BoundingBox>> boundingBoxes) {
107         int renderDistanceChunks = getRenderDistanceChunks();
108         int playerChunkX = MathHelper.floor(PlayerCoords.getX() / 16.0D);
109         int playerChunkZ = MathHelper.floor(PlayerCoords.getZ() / 16.0D);
110         for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; ++chunkX) {
111             for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; ++chunkZ) {
112                 if (isSlimeChunk(chunkX, chunkZ)) {
113                     int chunkXStart = chunkX << 4;
114                     int chunkZStart = chunkZ << 4;
115                     Coords minCoords = new Coords(chunkXStart, 1, chunkZStart);
116                     Coords maxCoords = new Coords(chunkXStart + 15, 38, chunkZStart + 15);
117                     boundingBoxes.put(BoundingBoxSlimeChunk.from(minCoords, maxCoords), null);
118                 }
119             }
120         }
121     }
122
123     private int getRenderDistanceChunks() {
124         return Minecraft.getInstance().gameSettings.renderDistanceChunks;
125     }
126
127     private boolean isSlimeChunk(int chunkX, int chunkZ) {
128         Random r = new Random(seed +
129                 (long) (chunkX * chunkX * 4987142) +
130                 (long) (chunkX * 5947611) +
131                 (long) (chunkZ * chunkZ) * 4392871L +
132                 (long) (chunkZ * 389711) ^ 987234911L);
133         return r.nextInt(10) == 0;
134     }
135
136     void setWorldData(long seed, int spawnX, int spawnZ) {
137         this.seed = seed;
138         spawnChunkBoundingBoxes = getSpawnChunkBoundingBoxes(spawnX, spawnZ);
139     }
140
141     private Set<BoundingBox> getSpawnChunkBoundingBoxes(int spawnX, int spawnZ) {
142         Set<BoundingBox> boundingBoxes = new HashSet<>();
143         boundingBoxes.add(getWorldSpawnBoundingBox(spawnX, spawnZ));
144         boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 12, BoundingBoxType.SpawnChunks));
145         boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 16, BoundingBoxType.LazySpawnChunks));
146         return boundingBoxes;
147     }
148
149     private BoundingBox getWorldSpawnBoundingBox(int spawnX, int spawnZ) {
150         Coords minCoords = new Coords(spawnX - 10, 0, spawnZ - 10);
151         Coords maxCoords = new Coords(spawnX + 10, 0, spawnZ + 10);
152
153         return BoundingBoxWorldSpawn.from(minCoords, maxCoords, BoundingBoxType.WorldSpawn);
154     }
155
156     private BoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ, int size, BoundingBoxType type) {
157         double midOffset = CHUNK_SIZE * (size / 2.0);
158         double midX = Math.round((float) (spawnX / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
159         double midZ = Math.round((float) (spawnZ / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
160         Coords minCoords = new Coords(midX - midOffset, 0, midZ - midOffset);
161         if (spawnX / (double) CHUNK_SIZE % 0.5D == 0.0D && spawnZ / (double) CHUNK_SIZE % 0.5D == 0.0D) {
162             midX += (double) CHUNK_SIZE;
163             midZ += (double) CHUNK_SIZE;
164         }
165         Coords maxCoords = new Coords(midX + midOffset, 0, midZ + midOffset);
166         return BoundingBoxWorldSpawn.from(minCoords, maxCoords, type);
167     }
168 }