Skip to content

Commit 3eb4234

Browse files
committed
improve fakeworld render performance
1 parent c00ffce commit 3eb4234

File tree

9 files changed

+171
-44
lines changed

9 files changed

+171
-44
lines changed

src/main/java/com/cleanroommc/modularui/utils/MathUtils.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,29 @@ public static float cos(float v) {
173173
public static float tan(float v) {
174174
return MathHelper.sin(v) / MathHelper.cos(v);
175175
}
176+
177+
public static double sqrt(double v) {
178+
return Math.sqrt(v);
179+
}
180+
181+
public static float sqrt(float v) {
182+
return (float) Math.sqrt(v);
183+
}
184+
185+
/**
186+
* Computes 1/sqrt(n) using <a href="https://en.wikipedia.org/wiki/Fast_inverse_square_root">the fast inverse square
187+
* root</a> with a constant of 0x5FE6EB50C7B537AA.
188+
*/
189+
public static double fastInvSqrt(double v) {
190+
double d0 = 0.5D * v;
191+
long i = Double.doubleToRawLongBits(v);
192+
i = 6910469410427058090L - (i >> 1);
193+
v = Double.longBitsToDouble(i);
194+
v = v * (1.5D - d0 * v * v);
195+
return v;
196+
}
197+
198+
public static float fastInvSqrt(float v) {
199+
return (float) fastInvSqrt((double) v);
200+
}
176201
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.cleanroommc.modularui.utils;
2+
3+
import com.google.common.collect.AbstractIterator;
4+
import org.apache.commons.lang3.tuple.MutablePair;
5+
import org.apache.commons.lang3.tuple.Pair;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
import java.util.ArrayList;
9+
import java.util.Iterator;
10+
import java.util.List;
11+
12+
public class PairList<T1, T2> implements Iterable<Pair<T1, T2>> {
13+
14+
private final List<T1> l1 = new ArrayList<>();
15+
private final List<T2> l2 = new ArrayList<>();
16+
17+
public void add(T1 t1, T2 t2) {
18+
this.l1.add(t1);
19+
this.l2.add(t2);
20+
}
21+
22+
public int size() {
23+
return this.l1.size();
24+
}
25+
26+
public boolean isEmpty() {
27+
return this.l1.isEmpty();
28+
}
29+
30+
public T1 getLeft(int index) {
31+
return this.l1.get(index);
32+
}
33+
34+
public T2 getRight(int index) {
35+
return this.l2.get(index);
36+
}
37+
38+
public Pair<T1, T2> get(int index) {
39+
return Pair.of(getLeft(index), getRight(index));
40+
}
41+
42+
@NotNull
43+
@Override
44+
public Iterator<Pair<T1, T2>> iterator() {
45+
return new AbstractIterator<>() {
46+
47+
private final MutablePair<T1, T2> pair = MutablePair.of(null, null);
48+
private int index = -1;
49+
50+
@Override
51+
protected Pair<T1, T2> computeNext() {
52+
if (++this.index == size()) return endOfData();
53+
this.pair.setLeft(getLeft(this.index));
54+
this.pair.setRight(getRight(this.index));
55+
return this.pair;
56+
}
57+
};
58+
}
59+
}

src/main/java/com/cleanroommc/modularui/utils/Vector3f.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public Vector3f normalise(Vector3f dest) {
221221
if (dest == null) dest = new Vector3f();
222222
float lsq = lengthSquared();
223223
if (lsq == 1) return dest.set(this);
224-
float f = (float) MathHelper.fastInvSqrt(lsq);
224+
float f = MathUtils.fastInvSqrt(lsq);
225225
dest.set(x * f, y * f, z * f);
226226
return dest;
227227
}

src/main/java/com/cleanroommc/modularui/utils/fakeworld/ArraySchema.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
import it.unimi.dsi.fastutil.chars.CharArraySet;
2020
import it.unimi.dsi.fastutil.chars.CharSet;
2121
import org.apache.commons.lang3.tuple.MutablePair;
22+
import org.apache.commons.lang3.tuple.Pair;
2223
import org.jetbrains.annotations.NotNull;
2324
import org.jetbrains.annotations.Nullable;
2425

2526
import java.util.ArrayList;
2627
import java.util.Iterator;
2728
import java.util.List;
28-
import java.util.Map;
2929
import java.util.function.BiPredicate;
3030

3131
public class ArraySchema implements ISchema {
@@ -120,15 +120,15 @@ public void setRenderFilter(@Nullable BiPredicate<BlockPos, BlockInfo> renderFil
120120

121121
@NotNull
122122
@Override
123-
public Iterator<Map.Entry<BlockPos, BlockInfo>> iterator() {
123+
public Iterator<Pair<BlockPos, BlockInfo>> iterator() {
124124
return new AbstractIterator<>() {
125125

126126
private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
127127
private final MutablePair<BlockPos, BlockInfo> pair = new MutablePair<>(pos, null);
128128
private int x = 0, y = 0, z = -1;
129129

130130
@Override
131-
protected Map.Entry<BlockPos, BlockInfo> computeNext() {
131+
protected Pair<BlockPos, BlockInfo> computeNext() {
132132
BlockInfo info;
133133
while (true) {
134134
if (++z >= blocks[x][y].length) {

src/main/java/com/cleanroommc/modularui/utils/fakeworld/BaseSchemaRenderer.java

Lines changed: 69 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
import org.lwjgl.opengl.GL11;
3838
import org.lwjgl.util.glu.GLU;
3939

40+
import java.util.ArrayList;
41+
import java.util.Iterator;
42+
import java.util.List;
43+
4044
public class BaseSchemaRenderer implements IDrawable {
4145

4246
private static final Framebuffer FBO = new Framebuffer(1080, 1080, true);
@@ -163,23 +167,14 @@ private void renderWorld() {
163167
GlStateManager.disableLighting();
164168
Platform.setupDrawGradient(); // needed for ambient occlusion
165169

170+
List<TileEntity> tesr = null;
166171
try { // render block in each layer
167172
for (BlockRenderLayer layer : BlockRenderLayer.values()) {
168-
ForgeHooksClient.setRenderLayer(layer);
169-
int pass = layer == BlockRenderLayer.TRANSLUCENT ? 1 : 0;
170-
setDefaultPassRenderState(pass);
171-
BufferBuilder buffer = Tessellator.getInstance().getBuffer();
172-
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
173-
BlockRendererDispatcher blockrendererdispatcher = mc.getBlockRendererDispatcher();
174-
this.schema.forEach(pair -> {
175-
BlockPos pos = pair.getKey();
176-
IBlockState state = pair.getValue().getBlockState();
177-
if (!state.getBlock().isAir(state, this.renderWorld, pos) && state.getBlock().canRenderInLayer(state, layer)) {
178-
blockrendererdispatcher.renderBlock(state, pos, this.renderWorld, buffer);
179-
}
180-
});
181-
Tessellator.getInstance().draw();
182-
Tessellator.getInstance().getBuffer().setTranslation(0, 0, 0);
173+
if (layer.ordinal() == 0 && isTesrEnabled()) {
174+
tesr = renderBlocksInLayer(mc, layer, true);
175+
} else {
176+
renderBlocksInLayer(mc, layer, false);
177+
}
183178
}
184179
} finally {
185180
ForgeHooksClient.setRenderLayer(oldRenderLayer);
@@ -188,29 +183,73 @@ private void renderWorld() {
188183
RenderHelper.enableStandardItemLighting();
189184
GlStateManager.enableLighting();
190185

191-
// render TESR
192-
if (isTesrEnabled()) {
193-
for (int pass = 0; pass < 2; pass++) {
194-
ForgeHooksClient.setRenderPass(pass);
195-
int finalPass = pass;
196-
GlStateManager.color(1, 1, 1, 1);
197-
setDefaultPassRenderState(pass);
198-
this.schema.forEach(pair -> {
199-
BlockPos pos = pair.getKey();
200-
TileEntity tile = pair.getValue().getTileEntity();
201-
if (tile != null && tile.shouldRenderInPass(finalPass)) {
202-
TileEntityRendererDispatcher.instance.render(tile, pos.getX(), pos.getY(), pos.getZ(), 0);
203-
}
204-
});
186+
try { // render TESR
187+
if (tesr != null && !tesr.isEmpty()) {
188+
renderTesr(tesr, 0);
189+
if (!tesr.isEmpty()) { // any tesr that don't render in pass 1 or 2 are removed from the list
190+
renderTesr(tesr, 1);
191+
renderTesr(tesr, 2);
192+
}
205193
}
194+
} finally {
195+
ForgeHooksClient.setRenderPass(-1);
206196
}
197+
207198
Platform.endDrawGradient();
208-
ForgeHooksClient.setRenderPass(-1);
209199
GlStateManager.enableDepth();
210200
GlStateManager.disableBlend();
211201
GlStateManager.depthMask(true);
212202
}
213203

204+
private List<TileEntity> renderBlocksInLayer(Minecraft mc, BlockRenderLayer layer, boolean collectTesr) {
205+
List<TileEntity> tesr = collectTesr ? new ArrayList<>() : null;
206+
ForgeHooksClient.setRenderLayer(layer);
207+
int pass = layer == BlockRenderLayer.TRANSLUCENT ? 1 : 0;
208+
setDefaultPassRenderState(pass);
209+
BufferBuilder buffer = Tessellator.getInstance().getBuffer();
210+
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
211+
BlockRendererDispatcher blockrendererdispatcher = mc.getBlockRendererDispatcher();
212+
this.schema.forEach(pair -> {
213+
BlockPos pos = pair.getKey();
214+
IBlockState state = pair.getValue().getBlockState();
215+
if (state.getBlock().isAir(state, this.renderWorld, pos)) return;
216+
if (collectTesr) {
217+
TileEntity te = pair.getValue().getTileEntity();
218+
if (te != null && !te.isInvalid()) {
219+
if (!te.getPos().equals(pos)) te.setPos(pos.toImmutable());
220+
if (TileEntityRendererDispatcher.instance.getRenderer(te.getClass()) != null) {
221+
// only collect tiles to render which actually have a tesr
222+
tesr.add(te);
223+
}
224+
}
225+
}
226+
if (state.getBlock().canRenderInLayer(state, layer)) {
227+
blockrendererdispatcher.renderBlock(state, pos, this.renderWorld, buffer);
228+
}
229+
});
230+
Tessellator.getInstance().draw();
231+
Tessellator.getInstance().getBuffer().setTranslation(0, 0, 0);
232+
return tesr;
233+
}
234+
235+
private static void renderTesr(List<TileEntity> tileEntities, int pass) {
236+
ForgeHooksClient.setRenderPass(pass);
237+
GlStateManager.color(1, 1, 1, 1);
238+
setDefaultPassRenderState(pass);
239+
for (Iterator<TileEntity> iterator = tileEntities.iterator(); iterator.hasNext(); ) {
240+
TileEntity tile = iterator.next();
241+
if (tile == null || tile.isInvalid()) continue;
242+
if (pass == 0 && (!tile.shouldRenderInPass(1) || !tile.shouldRenderInPass(2))) {
243+
// remove tiles that don't render in further passes
244+
iterator.remove();
245+
}
246+
if (tile.shouldRenderInPass(pass)) {
247+
BlockPos pos = tile.getPos();
248+
TileEntityRendererDispatcher.instance.render(tile, pos.getX(), pos.getY(), pos.getZ(), 0);
249+
}
250+
}
251+
}
252+
214253
private static void setDefaultPassRenderState(int pass) {
215254
GlStateManager.color(1, 1, 1, 1);
216255
if (pass == 0) { // SOLID

src/main/java/com/cleanroommc/modularui/utils/fakeworld/ISchema.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
import net.minecraft.util.math.Vec3d;
55
import net.minecraft.world.World;
66

7+
import org.apache.commons.lang3.tuple.Pair;
78
import org.jetbrains.annotations.Nullable;
89

9-
import java.util.Map;
1010
import java.util.function.BiPredicate;
1111

12-
public interface ISchema extends Iterable<Map.Entry<BlockPos, BlockInfo>> {
12+
public interface ISchema extends Iterable<Pair<BlockPos, BlockInfo>> {
1313

1414
World getWorld();
1515

src/main/java/com/cleanroommc/modularui/utils/fakeworld/MapSchema.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
1212
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
1313
import it.unimi.dsi.fastutil.objects.ObjectIterator;
14+
import org.apache.commons.lang3.tuple.MutablePair;
15+
import org.apache.commons.lang3.tuple.Pair;
1416
import org.jetbrains.annotations.NotNull;
1517
import org.jetbrains.annotations.Nullable;
1618

@@ -80,17 +82,20 @@ public BlockPos getOrigin() {
8082

8183
@NotNull
8284
@Override
83-
public Iterator<Map.Entry<BlockPos, BlockInfo>> iterator() {
85+
public Iterator<Pair<BlockPos, BlockInfo>> iterator() {
8486
return new AbstractIterator<>() {
8587

8688
private final ObjectIterator<Object2ObjectMap.Entry<BlockPos, BlockInfo>> it = blocks.object2ObjectEntrySet().fastIterator();
89+
private final MutablePair<BlockPos, BlockInfo> pair = new MutablePair<>(null, null);
8790

8891
@Override
89-
protected Map.Entry<BlockPos, BlockInfo> computeNext() {
92+
protected Pair<BlockPos, BlockInfo> computeNext() {
9093
while (it.hasNext()) {
9194
Map.Entry<BlockPos, BlockInfo> entry = it.next();
9295
if (renderFilter == null || renderFilter.test(entry.getKey(), entry.getValue())) {
93-
return entry;
96+
pair.setLeft(entry.getKey());
97+
pair.setRight(entry.getValue());
98+
return pair;
9499
}
95100
}
96101
return endOfData();

src/main/java/com/cleanroommc/modularui/utils/fakeworld/PosListSchema.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import org.jetbrains.annotations.Nullable;
1010

1111
import java.util.Iterator;
12-
import java.util.Map;
1312
import java.util.function.BiPredicate;
1413

1514
public abstract class PosListSchema implements ISchema {
@@ -41,7 +40,7 @@ public World getWorld() {
4140

4241
@NotNull
4342
@Override
44-
public Iterator<Map.Entry<BlockPos, BlockInfo>> iterator() {
43+
public Iterator<Pair<BlockPos, BlockInfo>> iterator() {
4544
return new Iterator<>() {
4645

4746
private final Iterator<? extends BlockPos> posIt = PosListSchema.this.posList.iterator();

src/main/java/com/cleanroommc/modularui/utils/fakeworld/SchemaWorld.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
1010
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
1111
import org.apache.commons.lang3.tuple.MutablePair;
12+
import org.apache.commons.lang3.tuple.Pair;
1213
import org.jetbrains.annotations.NotNull;
1314
import org.jetbrains.annotations.Nullable;
1415

1516
import java.util.Iterator;
16-
import java.util.Map;
1717
import java.util.function.BiPredicate;
1818

1919
public class SchemaWorld extends DummyWorld implements ISchema {
@@ -95,14 +95,14 @@ public BlockPos getOrigin() {
9595

9696
@NotNull
9797
@Override
98-
public Iterator<Map.Entry<BlockPos, BlockInfo>> iterator() {
98+
public Iterator<Pair<BlockPos, BlockInfo>> iterator() {
9999
return new AbstractIterator<>() {
100100
private final ObjectListIterator<BlockPos> it = blocks.iterator();
101101
private final BlockInfo.Mut info = new BlockInfo.Mut();
102102
private final MutablePair<BlockPos, BlockInfo> pair = new MutablePair<>(null, this.info);
103103

104104
@Override
105-
protected Map.Entry<BlockPos, BlockInfo> computeNext() {
105+
protected Pair<BlockPos, BlockInfo> computeNext() {
106106
while (it.hasNext()) {
107107
var pos = it.next();
108108
this.info.set(SchemaWorld.this, pos);

0 commit comments

Comments
 (0)