-
Notifications
You must be signed in to change notification settings - Fork 205
Replace ImmediateWorldSceneRenderer with VBOWorldSceneRenderer
#2849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e4bfd6f
65b24ea
10fe768
28b93c6
db9c150
a28af9c
5f6805b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package net.optifine.shaders; | ||
|
|
||
| import net.minecraft.util.BlockRenderLayer; | ||
|
|
||
| /// Adapted and minimized from OptiFine | ||
| public class ShadersRender { | ||
|
|
||
| public static void preRenderChunkLayer(BlockRenderLayer blockLayerIn) {} | ||
|
|
||
| public static void postRenderChunkLayer(BlockRenderLayer blockLayerIn) {} | ||
|
|
||
| public static void setupArrayPointersVbo() {} | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| package gregtech.client.renderer.scene; | ||
|
|
||
| import gregtech.api.util.Mods; | ||
| import gregtech.client.utils.OptiFineHelper; | ||
|
|
||
| import net.minecraft.client.Minecraft; | ||
| import net.minecraft.client.renderer.*; | ||
| import net.minecraft.client.renderer.texture.TextureMap; | ||
| import net.minecraft.client.renderer.vertex.DefaultVertexFormats; | ||
| import net.minecraft.client.renderer.vertex.VertexBuffer; | ||
| import net.minecraft.client.renderer.vertex.VertexFormatElement; | ||
| import net.minecraft.util.BlockRenderLayer; | ||
| import net.minecraft.util.math.BlockPos; | ||
| import net.minecraft.world.World; | ||
| import net.minecraftforge.client.ForgeHooksClient; | ||
| import net.minecraftforge.client.MinecraftForgeClient; | ||
| import net.minecraftforge.fml.relauncher.Side; | ||
| import net.minecraftforge.fml.relauncher.SideOnly; | ||
| import net.optifine.shaders.ShadersRender; | ||
|
|
||
| import org.lwjgl.opengl.GL11; | ||
|
|
||
| import java.util.Collection; | ||
|
|
||
| @SideOnly(Side.CLIENT) | ||
| public class VBOWorldSceneRenderer extends ImmediateWorldSceneRenderer { | ||
|
|
||
| protected static final VertexBuffer[] VBOS = new VertexBuffer[BlockRenderLayer.values().length]; | ||
| protected boolean isDirty = true; | ||
|
|
||
| public VBOWorldSceneRenderer(World world) { | ||
| super(world); | ||
| } | ||
|
|
||
| private void uploadVBO() { | ||
| BlockRenderLayer oldRenderLayer = MinecraftForgeClient.getRenderLayer(); | ||
|
|
||
| try { // render block in each layer | ||
| for (BlockRenderLayer layer : BlockRenderLayer.values()) { | ||
|
|
||
| OptiFineHelper.preRenderChunkLayer(layer); | ||
|
|
||
| renderBlockLayer(layer); | ||
|
|
||
| // Get the buffer again | ||
| BufferBuilder buffer = Tessellator.getInstance().getBuffer(); | ||
| buffer.finishDrawing(); | ||
| buffer.reset(); | ||
|
|
||
| int i = layer.ordinal(); | ||
| var vbo = VBOS[i]; | ||
| if (vbo == null) vbo = VBOS[i] = new VertexBuffer(DefaultVertexFormats.BLOCK); | ||
| vbo.bufferData(buffer.getByteBuffer()); | ||
|
|
||
| OptiFineHelper.postRenderChunkLayer(layer); | ||
| } | ||
| } finally { | ||
| ForgeHooksClient.setRenderLayer(oldRenderLayer); | ||
| } | ||
| this.isDirty = false; | ||
| } | ||
|
|
||
| @Override | ||
| protected void drawWorld() { | ||
| if (this.isDirty) { | ||
| uploadVBO(); | ||
| } | ||
| if (beforeRender != null) { | ||
| beforeRender.accept(this); | ||
| } | ||
|
|
||
| Minecraft mc = Minecraft.getMinecraft(); | ||
| GlStateManager.enableCull(); | ||
| GlStateManager.enableRescaleNormal(); | ||
| RenderHelper.disableStandardItemLighting(); | ||
| mc.entityRenderer.disableLightmap(); | ||
| mc.renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); | ||
| GlStateManager.disableLighting(); | ||
| GlStateManager.enableTexture2D(); | ||
| GlStateManager.enableAlpha(); | ||
|
|
||
| var oldRenderLayer = MinecraftForgeClient.getRenderLayer(); | ||
| for (var layer : BlockRenderLayer.values()) { | ||
|
|
||
| ForgeHooksClient.setRenderLayer(layer); | ||
|
|
||
| int pass = layer == BlockRenderLayer.TRANSLUCENT ? 1 : 0; | ||
| setDefaultPassRenderState(pass); | ||
|
|
||
| OptiFineHelper.preRenderChunkLayer(layer); | ||
|
|
||
| GlStateManager.pushMatrix(); | ||
| { | ||
| int i = layer.ordinal(); | ||
| var vbo = VBOS[i]; | ||
| vbo.bindBuffer(); | ||
| enableClientStates(); | ||
| setupArrayPointers(); | ||
| vbo.drawArrays(GL11.GL_QUADS); | ||
| disableClientStates(); | ||
| vbo.unbindBuffer(); | ||
| } | ||
| GlStateManager.popMatrix(); | ||
|
|
||
| OptiFineHelper.postRenderChunkLayer(layer); | ||
| } | ||
| ForgeHooksClient.setRenderLayer(oldRenderLayer); | ||
|
|
||
| renderTileEntities(); // Handle TileEntities | ||
|
|
||
| GlStateManager.shadeModel(GL11.GL_SMOOTH); | ||
| RenderHelper.enableStandardItemLighting(); | ||
| GlStateManager.enableDepth(); | ||
| GlStateManager.disableBlend(); | ||
| GlStateManager.depthMask(true); | ||
|
|
||
| if (afterRender != null) { | ||
| afterRender.accept(this); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public WorldSceneRenderer addRenderedBlocks(Collection<BlockPos> blocks) { | ||
| this.isDirty = true; | ||
| return super.addRenderedBlocks(blocks); | ||
| } | ||
|
|
||
| protected void enableClientStates() { | ||
| GlStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY); | ||
| OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); | ||
| GlStateManager.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); | ||
| OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); | ||
| GlStateManager.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); | ||
| OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); | ||
| GlStateManager.glEnableClientState(GL11.GL_COLOR_ARRAY); | ||
| } | ||
|
|
||
| protected void disableClientStates() { | ||
| for (VertexFormatElement element : DefaultVertexFormats.BLOCK.getElements()) { | ||
| switch (element.getUsage()) { | ||
| case POSITION -> GlStateManager.glDisableClientState(GL11.GL_VERTEX_ARRAY); | ||
| case COLOR -> GlStateManager.glDisableClientState(GL11.GL_COLOR_ARRAY); | ||
| case UV -> { | ||
| OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit + element.getIndex()); | ||
| GlStateManager.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); | ||
| OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); | ||
| } | ||
| default -> {} | ||
| } | ||
| } | ||
| } | ||
|
|
||
| protected void setupArrayPointers() { | ||
| if (Mods.ShadersMod.isModLoaded()) { | ||
| ShadersRender.setupArrayPointersVbo(); | ||
| } else { | ||
| // 28 == DefaultVertexFormats.BLOCK.getSize(); | ||
| GlStateManager.glVertexPointer(3, GL11.GL_FLOAT, 28, 0); | ||
| GlStateManager.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 28, 12); | ||
| GlStateManager.glTexCoordPointer(2, GL11.GL_FLOAT, 28, 16); | ||
| OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); | ||
| GlStateManager.glTexCoordPointer(2, GL11.GL_SHORT, 28, 24); | ||
| OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| package gregtech.client.renderer.scene; | ||
|
|
||
| import gregtech.api.metatileentity.IFastRenderMetaTileEntity; | ||
| import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; | ||
| import gregtech.api.util.Position; | ||
| import gregtech.api.util.PositionedRect; | ||
| import gregtech.api.util.Size; | ||
|
|
@@ -25,6 +27,7 @@ | |
| import net.minecraftforge.fml.relauncher.SideOnly; | ||
|
|
||
| import codechicken.lib.vec.Vector3; | ||
| import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; | ||
| import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.lwjgl.opengl.GL11; | ||
|
|
@@ -35,6 +38,7 @@ | |
| import java.nio.FloatBuffer; | ||
| import java.nio.IntBuffer; | ||
| import java.util.Collection; | ||
| import java.util.Map; | ||
| import java.util.function.Consumer; | ||
|
|
||
| import javax.vecmath.Vector3f; | ||
|
|
@@ -60,10 +64,12 @@ public abstract class WorldSceneRenderer { | |
| protected static final FloatBuffer OBJECT_POS_BUFFER = ByteBuffer.allocateDirect(3 * 4) | ||
| .order(ByteOrder.nativeOrder()).asFloatBuffer(); | ||
|
|
||
| // In most cases this would be empty | ||
| protected static final Map<BlockPos, TileEntity> TILE_ENTITIES = new Object2ObjectArrayMap<>(); | ||
| public final World world; | ||
| public final Collection<BlockPos> renderedBlocks = new ObjectOpenHashSet<>(); | ||
| private Consumer<WorldSceneRenderer> beforeRender; | ||
| private Consumer<WorldSceneRenderer> afterRender; | ||
| protected Consumer<WorldSceneRenderer> beforeRender; | ||
| protected Consumer<WorldSceneRenderer> afterRender; | ||
| private Consumer<RayTraceResult> onLookingAt; | ||
| private int clearColor; | ||
| private RayTraceResult lastTraceResult; | ||
|
|
@@ -88,6 +94,15 @@ public WorldSceneRenderer setAfterWorldRender(Consumer<WorldSceneRenderer> callb | |
| public WorldSceneRenderer addRenderedBlocks(@Nullable Collection<BlockPos> blocks) { | ||
| if (blocks != null) { | ||
| this.renderedBlocks.addAll(blocks); | ||
| TILE_ENTITIES.clear(); | ||
| blocks.forEach(pos -> { | ||
| TileEntity tile = world.getTileEntity(pos); | ||
| if (tile != null && (!(tile instanceof IGregTechTileEntity gtte) || | ||
| // Put MTEs only when it has FastRenderer | ||
| gtte.getMetaTileEntity() instanceof IFastRenderMetaTileEntity)) { | ||
| TILE_ENTITIES.put(pos, tile); | ||
| } | ||
| }); | ||
| } | ||
| return this; | ||
| } | ||
|
|
@@ -237,23 +252,8 @@ protected void drawWorld() { | |
|
|
||
| try { // render block in each layer | ||
| for (BlockRenderLayer layer : BlockRenderLayer.values()) { | ||
| ForgeHooksClient.setRenderLayer(layer); | ||
| int pass = layer == BlockRenderLayer.TRANSLUCENT ? 1 : 0; | ||
| setDefaultPassRenderState(pass); | ||
|
|
||
| BufferBuilder buffer = Tessellator.getInstance().getBuffer(); | ||
| buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); | ||
| BlockRendererDispatcher blockrendererdispatcher = mc.getBlockRendererDispatcher(); | ||
|
|
||
| for (BlockPos pos : renderedBlocks) { | ||
| IBlockState state = world.getBlockState(pos); | ||
| Block block = state.getBlock(); | ||
| if (block == Blocks.AIR) continue; | ||
| state = state.getActualState(world, pos); | ||
| if (block.canRenderInLayer(state, layer)) { | ||
| blockrendererdispatcher.renderBlock(state, pos, world, buffer); | ||
| } | ||
| } | ||
|
|
||
| renderBlockLayer(layer); | ||
|
|
||
| Tessellator.getInstance().draw(); | ||
| Tessellator.getInstance().getBuffer().setTranslation(0, 0, 0); | ||
|
|
@@ -262,23 +262,8 @@ protected void drawWorld() { | |
| ForgeHooksClient.setRenderLayer(oldRenderLayer); | ||
| } | ||
|
|
||
| RenderHelper.enableStandardItemLighting(); | ||
| GlStateManager.enableLighting(); | ||
| renderTileEntities(); // Handle TileEntities | ||
|
|
||
| // render TESR | ||
| for (int pass = 0; pass < 2; pass++) { | ||
| ForgeHooksClient.setRenderPass(pass); | ||
| setDefaultPassRenderState(pass); | ||
| for (BlockPos pos : renderedBlocks) { | ||
| TileEntity tile = world.getTileEntity(pos); | ||
| if (tile != null) { | ||
| if (tile.shouldRenderInPass(pass)) { | ||
| TileEntityRendererDispatcher.instance.render(tile, pos.getX(), pos.getY(), pos.getZ(), 0); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ForgeHooksClient.setRenderPass(-1); | ||
| GlStateManager.enableDepth(); | ||
| GlStateManager.disableBlend(); | ||
| GlStateManager.depthMask(true); | ||
|
|
@@ -288,6 +273,44 @@ protected void drawWorld() { | |
| } | ||
| } | ||
|
|
||
| protected void renderBlockLayer(BlockRenderLayer layer) { | ||
| ForgeHooksClient.setRenderLayer(layer); | ||
| int pass = layer == BlockRenderLayer.TRANSLUCENT ? 1 : 0; | ||
| setDefaultPassRenderState(pass); | ||
|
|
||
| BufferBuilder buffer = Tessellator.getInstance().getBuffer(); | ||
| buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); | ||
| BlockRendererDispatcher blockrendererdispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher(); | ||
|
|
||
| for (BlockPos pos : renderedBlocks) { | ||
| IBlockState state = world.getBlockState(pos); | ||
| Block block = state.getBlock(); | ||
| if (block == Blocks.AIR) continue; | ||
MCTian-mi marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be a call to Block.isAir() instead?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was |
||
| state = state.getActualState(world, pos); | ||
| if (block.canRenderInLayer(state, layer)) { | ||
| blockrendererdispatcher.renderBlock(state, pos, world, buffer); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| protected void renderTileEntities() { | ||
| RenderHelper.enableStandardItemLighting(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this not also call GLSM lighting like the original method?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the |
||
| var dispatcher = TileEntityRendererDispatcher.instance; | ||
| for (int pass = 0; pass < 2; pass++) { | ||
| ForgeHooksClient.setRenderPass(pass); | ||
| setDefaultPassRenderState(pass); | ||
|
|
||
| int finalPass = pass; | ||
| TILE_ENTITIES.forEach((pos, tile) -> { | ||
| if (tile.shouldRenderInPass(finalPass)) { | ||
| dispatcher.render(tile, pos.getX(), pos.getY(), pos.getZ(), 0); | ||
| } | ||
| }); | ||
| } | ||
| ForgeHooksClient.setRenderPass(-1); | ||
| RenderHelper.disableStandardItemLighting(); | ||
| } | ||
|
|
||
| public static void setDefaultPassRenderState(int pass) { | ||
| GlStateManager.color(1, 1, 1, 1); | ||
| if (pass == 0) { // SOLID | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package gregtech.client.utils; | ||
|
|
||
| import gregtech.api.util.Mods; | ||
|
|
||
| import net.minecraft.util.BlockRenderLayer; | ||
| import net.optifine.shaders.ShadersRender; | ||
|
|
||
| public class OptiFineHelper { | ||
|
|
||
| public static BlockRenderLayer getOFSafeLayer(BlockRenderLayer layer) { | ||
| if (!Mods.ShadersMod.isModLoaded()) return layer; | ||
| return layer == BloomEffectUtil.getBloomLayer() ? BloomEffectUtil.getEffectiveBloomLayer() : layer; | ||
| } | ||
|
|
||
| public static void preRenderChunkLayer(BlockRenderLayer layer) { | ||
| if (Mods.ShadersMod.isModLoaded()) { | ||
| ShadersRender.preRenderChunkLayer(getOFSafeLayer(layer)); | ||
| } | ||
| } | ||
|
|
||
| public static void postRenderChunkLayer(BlockRenderLayer layer) { | ||
| if (Mods.ShadersMod.isModLoaded()) { | ||
| ShadersRender.postRenderChunkLayer(getOFSafeLayer(layer)); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ | |
| import gregtech.api.util.GregFakePlayer; | ||
| import gregtech.api.util.ItemStackHashStrategy; | ||
| import gregtech.client.renderer.scene.ImmediateWorldSceneRenderer; | ||
| import gregtech.client.renderer.scene.VBOWorldSceneRenderer; | ||
| import gregtech.client.renderer.scene.WorldSceneRenderer; | ||
| import gregtech.client.utils.RenderUtil; | ||
| import gregtech.client.utils.TrackedDummyWorld; | ||
|
|
@@ -585,7 +586,7 @@ private MBPattern initializePattern(@NotNull MultiblockShapeInfo shapeInfo, @Not | |
| } | ||
|
|
||
| TrackedDummyWorld world = new TrackedDummyWorld(); | ||
| ImmediateWorldSceneRenderer worldSceneRenderer = new ImmediateWorldSceneRenderer(world); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this was the only place where ImmediateWorldSceneRenderer was used, should we go ahead and fold the methods into VBOWorldSceneRenderer and delete the class?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was used in terminal I think, but yeah ig we could safely delete this since mui has its own world renderer impl that is exactly the same as |
||
| ImmediateWorldSceneRenderer worldSceneRenderer = new VBOWorldSceneRenderer(world); | ||
| worldSceneRenderer.setClearColor(ConfigHolder.client.multiblockPreviewColor); | ||
| world.addBlocks(blockMap); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a spot where this should be cleared? Besides when recalculating the TEs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know, actually. The renderer itself won't get GC'ed when used in JEI plugin, neither did I found a proper place to call clear on this, so I just made this cleared where
renderedBlocksgot cleared.I think it might be ok since there's < 1 elements in the map by average?
Or should I use a
Cacheso it got automatically invalidated?