]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/client/ClientRenderer.java
Several fixes
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / client / ClientRenderer.java
1 package com.irtimaled.bbor.client;
2
3 import com.irtimaled.bbor.client.config.ConfigManager;
4 import com.irtimaled.bbor.client.interop.ClientInterop;
5 import com.irtimaled.bbor.client.interop.TileEntitiesHelper;
6 import com.irtimaled.bbor.client.models.Point;
7 import com.irtimaled.bbor.client.providers.BeaconProvider;
8 import com.irtimaled.bbor.client.providers.BedrockCeilingProvider;
9 import com.irtimaled.bbor.client.providers.BiomeBorderProvider;
10 import com.irtimaled.bbor.client.providers.ConduitProvider;
11 import com.irtimaled.bbor.client.providers.CustomBeaconProvider;
12 import com.irtimaled.bbor.client.providers.CustomBoxProvider;
13 import com.irtimaled.bbor.client.providers.CustomLineProvider;
14 import com.irtimaled.bbor.client.providers.CustomSphereProvider;
15 import com.irtimaled.bbor.client.providers.FlowerForestProvider;
16 import com.irtimaled.bbor.client.providers.IBoundingBoxProvider;
17 import com.irtimaled.bbor.client.providers.ICachingProvider;
18 import com.irtimaled.bbor.client.providers.MobSpawnerProvider;
19 import com.irtimaled.bbor.client.providers.SlimeChunkProvider;
20 import com.irtimaled.bbor.client.providers.SpawnableBlocksProvider;
21 import com.irtimaled.bbor.client.providers.SpawningSphereProvider;
22 import com.irtimaled.bbor.client.providers.WorldSpawnProvider;
23 import com.irtimaled.bbor.client.renderers.AbstractRenderer;
24 import com.irtimaled.bbor.client.renderers.RenderHelper;
25 import com.irtimaled.bbor.client.renderers.RenderQueue;
26 import com.irtimaled.bbor.common.MathHelper;
27 import com.irtimaled.bbor.common.TypeHelper;
28 import com.irtimaled.bbor.common.models.AbstractBoundingBox;
29 import com.irtimaled.bbor.common.models.DimensionId;
30 import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
31 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
32 import it.unimi.dsi.fastutil.objects.ObjectArrayList;
33 import net.fabricmc.api.EnvType;
34 import net.fabricmc.loader.api.FabricLoader;
35 import net.minecraft.client.util.math.MatrixStack;
36
37 import java.util.Comparator;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.concurrent.atomic.AtomicLong;
43 import java.util.function.Supplier;
44
45 public class ClientRenderer {
46     private static final int CHUNK_SIZE = 16;
47     private static final Map<Class<? extends AbstractBoundingBox>, AbstractRenderer> boundingBoxRendererMap = Object2ObjectMaps.synchronize(new Object2ObjectOpenHashMap<>());
48
49     private static boolean active;
50     private static final Set<IBoundingBoxProvider> providers = new HashSet<>();
51
52     private static AtomicLong lastDurationNanos = new AtomicLong(0L);
53
54     public static boolean getActive() {
55         return active;
56     }
57
58     public static void toggleActive() {
59         active = !active;
60         if (!active) return;
61
62         Player.setActiveY();
63     }
64
65     static void deactivate() {
66         active = false;
67     }
68
69     static {
70         registerProvider(new SlimeChunkProvider());
71         registerProvider(new WorldSpawnProvider());
72         registerProvider(new SpawningSphereProvider());
73         registerProvider(new BeaconProvider());
74         registerProvider(new CustomBoxProvider());
75         registerProvider(new CustomBeaconProvider());
76         registerProvider(new BiomeBorderProvider());
77         registerProvider(new MobSpawnerProvider());
78         registerProvider(new ConduitProvider());
79         registerProvider(new SpawnableBlocksProvider());
80         registerProvider(new CustomLineProvider());
81         registerProvider(new CustomSphereProvider());
82         registerProvider(new FlowerForestProvider());
83         registerProvider(new BedrockCeilingProvider());
84     }
85
86     public static <T extends AbstractBoundingBox> void registerProvider(IBoundingBoxProvider<T> provider) {
87         providers.add(provider);
88     }
89
90     public static <T extends AbstractBoundingBox> AbstractRenderer<T> registerRenderer(Class<? extends T> type, Supplier<AbstractRenderer<T>> renderer) {
91         if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) return null;
92         final AbstractRenderer<T> renderer1 = renderer.get();
93         boundingBoxRendererMap.put(type, renderer1);
94         return renderer1;
95     }
96
97     public static AbstractRenderer getRenderer(Class<? extends AbstractBoundingBox> clazz) {
98         return boundingBoxRendererMap.get(clazz);
99     }
100
101     private static boolean isWithinRenderDistance(AbstractBoundingBox boundingBox) {
102         int renderDistanceBlocks = ClientInterop.getRenderDistanceChunks() * CHUNK_SIZE;
103         int minX = MathHelper.floor(Player.getX() - renderDistanceBlocks);
104         int maxX = MathHelper.floor(Player.getX() + renderDistanceBlocks);
105         int minZ = MathHelper.floor(Player.getZ() - renderDistanceBlocks);
106         int maxZ = MathHelper.floor(Player.getZ() + renderDistanceBlocks);
107
108         return boundingBox.intersectsBounds(minX, minZ, maxX, maxZ);
109     }
110
111     public static void render(MatrixStack matrixStack, DimensionId dimensionId) {
112         if (!active) return;
113
114         long startTime = System.nanoTime();
115         matrixStack.push();
116         RenderHelper.beforeRender();
117         TileEntitiesHelper.clearCache();
118
119         final List<AbstractBoundingBox> boundingBoxes = getBoundingBoxes(dimensionId);
120         RenderCulling.flushPreRendering();
121         for (AbstractBoundingBox key : boundingBoxes) {
122             AbstractRenderer renderer = key.getRenderer();
123             if (renderer != null) renderer.render(matrixStack, key);
124         }
125
126         RenderQueue.renderDeferred();
127
128         RenderHelper.afterRender();
129         RenderCulling.flushRendering();
130         matrixStack.pop();
131         lastDurationNanos.set(System.nanoTime() - startTime);
132     }
133
134     private static final ObjectArrayList<AbstractBoundingBox> listForRendering = new ObjectArrayList<>();
135
136     public static List<AbstractBoundingBox> getBoundingBoxes(DimensionId dimensionId) {
137         listForRendering.clear();
138         final boolean doPreCulling = ConfigManager.fastRender.get() >= 2;
139         for (IBoundingBoxProvider<?> provider : providers) {
140             if (provider.canProvide(dimensionId)) {
141                 for (AbstractBoundingBox boundingBox : provider.get(dimensionId)) {
142                     if (isWithinRenderDistance(boundingBox)) {
143                         if (doPreCulling && !boundingBox.isVisibleCulling()) continue;
144                         listForRendering.add(boundingBox);
145                     }
146                 }
147             }
148         }
149
150         Point point = Player.getPoint();
151         listForRendering.sort(Comparator.comparingDouble((AbstractBoundingBox boundingBox) -> boundingBox.getDistance(point.getX(), point.getY(), point.getZ())).reversed());
152
153         return listForRendering;
154     }
155
156     public static void clear() {
157         for(IBoundingBoxProvider<?> provider : providers) {
158             TypeHelper.doIfType(provider, ICachingProvider.class, ICachingProvider::clearCache);
159         }
160     }
161
162     public static long getLastDurationNanos() {
163         return lastDurationNanos.get();
164     }
165
166
167 }