From 1b0f93db07eb071eb74294a58e6e4e6f385acf7d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 10 Mar 2026 11:40:36 -0500 Subject: [PATCH] Changes for blaze/gl rendering config --- core/build.gradle | 10 +- .../core/api/internal/ClientApi.java | 28 +- .../distanthorizons/core/config/Config.java | 3 +- .../bufferBuilding/LodBufferContainer.java | 4 +- .../render/bufferBuilding/LodQuadBuilder.java | 19 +- .../core/logging/f3/F3Screen.java | 5 + .../core/render/DhApiRenderProxy.java | 4 +- .../core/render/RenderBufferHandler.java | 4 +- .../core/render/RenderParams.java | 4 +- .../core/render/RenderThreadTaskHandler.java | 2 +- .../renderer/GenericRenderObjectFactory.java | 75 ++++ ...BlazeLodRenderer.java => LodRenderer.java} | 50 +-- .../render/renderer/RenderableBoxGroup.java | 361 ++++++++++++++++++ .../render/AbstractDhRenderApiDefinition.java | 12 + .../render/renderPass/IDhTerrainRenderer.java | 4 +- .../assets/distanthorizons/lang/en_us.json | 15 +- core/src/main/resources/shaders/standard.vert | 2 +- 17 files changed, 535 insertions(+), 67 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericRenderObjectFactory.java rename core/src/main/java/com/seibel/distanthorizons/core/render/renderer/{BlazeLodRenderer.java => LodRenderer.java} (93%) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/renderer/RenderableBoxGroup.java diff --git a/core/build.gradle b/core/build.gradle index a2cbb828e..0af80900f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -28,15 +28,17 @@ dependencies { // All of these dependencies are in Vanilla Minecraft, but we nee implementation "org.lwjgl:lwjgl" implementation "org.lwjgl:lwjgl-assimp" implementation "org.lwjgl:lwjgl-glfw" - implementation "org.lwjgl:lwjgl-openal" - implementation "org.lwjgl:lwjgl-opengl" + // OpenGL is removed since DH now handles rendering in the "Common" project + // so we can use OpenGL for old MC versions and Blaze3D (IE Vulkan) for newer ones +// implementation "org.lwjgl:lwjgl-openal" +// implementation "org.lwjgl:lwjgl-opengl" implementation "org.lwjgl:lwjgl-stb" implementation "org.lwjgl:lwjgl-tinyfd" runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives" - runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives" +// runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives" +// runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives" diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java index 5f39d0084..c21c905e8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java @@ -40,6 +40,7 @@ import com.seibel.distanthorizons.core.util.objects.Pair; import com.seibel.distanthorizons.core.util.objects.RollingAverage; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; @@ -595,7 +596,7 @@ public class ClientApi boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderEvent.class, renderParams); if (!renderingCancelled) { - BlazeLodRenderer.INSTANCE.render(renderParams, profiler); + LodRenderer.INSTANCE.render(renderParams, profiler); } if (!DhApi.Delayed.renderProxy.getDeferTransparentRendering()) @@ -608,7 +609,7 @@ public class ClientApi boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDeferredRenderEvent.class, renderParams); if (!renderingCancelled) { - BlazeLodRenderer.INSTANCE.renderDeferred(renderParams, profiler); + LodRenderer.INSTANCE.renderDeferred(renderParams, profiler); } @@ -620,14 +621,23 @@ public class ClientApi } else { - IDhTestTriangleRenderer testRenderer = SingletonInjector.INSTANCE.get(IDhTestTriangleRenderer.class); - if (testRenderer != null) + if (!renderingDeferredLayer) { - testRenderer.render(); - } - else - { - RATE_LIMITED_LOGGER.warn("Unable to find singleton ["+ IDhTestTriangleRenderer.class.getSimpleName()+"]"); + IDhTerrainRenderer lodRenderer = SingletonInjector.INSTANCE.get(IDhTerrainRenderer.class); + IDhTestTriangleRenderer testRenderer = SingletonInjector.INSTANCE.get(IDhTestTriangleRenderer.class); + if (testRenderer != null + && lodRenderer != null) + { + lodRenderer.runRenderPassSetup(renderParams); + + testRenderer.render(); + + lodRenderer.runRenderPassCleanup(renderParams); + } + else + { + RATE_LIMITED_LOGGER.warn("Unable to find singleton [" + IDhTestTriangleRenderer.class.getSimpleName() + "]"); + } } } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index cfe1a8f8b..f50bbc810 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -835,8 +835,9 @@ public class Config public static ConfigEntry renderingApi = new ConfigEntry.Builder() .set(EDhApiRenderApi.AUTO) - .setAppearance(EConfigEntryAppearance.ONLY_IN_FILE) // can't be changed while the game is running .comment("" + + "Requires a restart to change. \n" + + " \n" + "Options: \n" + EDhApiRenderApi.AUTO + " \n" + EDhApiRenderApi.OPEN_GL + " \n" diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodBufferContainer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodBufferContainer.java index 60933fd64..16e397082 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodBufferContainer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodBufferContainer.java @@ -215,11 +215,9 @@ public class LodBufferContainer implements AutoCloseable } IVertexBufferWrapper vbo = vbos[vboIndex]; - IDhTerrainRenderer lodRenderer = SingletonInjector.INSTANCE.get(IDhTerrainRenderer.class); - ByteBuffer buffer = byteBuffers.get(i); int size = buffer.limit() - buffer.position(); - int vertexCount = size / lodRenderer.getVertexByteSize(); + int vertexCount = size / LodQuadBuilder.BYTES_PER_VERTEX; try { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java index 4c6b87e44..5735638d3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java @@ -57,7 +57,8 @@ public class LodQuadBuilder private final EDhApiDebugRendering debugRenderingMode; private final EDhApiGrassSideRendering grassSideRenderingMode; - + /** the number of bytes for */ + public static final int BYTES_PER_VERTEX = 14; public static final int[][][] DIRECTION_VERTEX_IBO_QUAD = new int[][][] ///region @@ -117,6 +118,7 @@ public class LodQuadBuilder //=============// // constructor // //=============// + //region public LodQuadBuilder(boolean doTransparency, IClientLevelWrapper clientLevelWrapper) { @@ -134,6 +136,8 @@ public class LodQuadBuilder } + //endregion + //===========// @@ -482,6 +486,11 @@ public class LodQuadBuilder } private static int maxBufferByteSize = -1; + /** + * The max number of bytes we allow for a single Vertex buffer. + * If an LOD has more data than this it will be split + * up into multiple buffers. + */ public static int getMaxBufferByteSize() { if (maxBufferByteSize != -1) @@ -489,11 +498,9 @@ public class LodQuadBuilder return maxBufferByteSize; } - IDhTerrainRenderer LOD_RENDERER = SingletonInjector.INSTANCE.get(IDhTerrainRenderer.class); - - /** number of bytes a single quad takes */ - int QUADS_BYTE_SIZE = LOD_RENDERER.getVertexByteSize() * 4; - /** how big a single VBO can be in bytes */ + // number of bytes a single quad takes + int QUADS_BYTE_SIZE = BYTES_PER_VERTEX * 4; + // how big a single VBO can be in bytes int MAX_VBO_BYTE_SIZE = 10 * 1024 * 1024; // 10 MB int MAX_QUADS_PER_BUFFER = MAX_VBO_BYTE_SIZE / QUADS_BYTE_SIZE; int FULL_SIZED_BUFFER = MAX_QUADS_PER_BUFFER * QUADS_BYTE_SIZE; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java b/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java index 2bc9a08bf..49d9026ee 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java @@ -35,6 +35,7 @@ import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.world.AbstractDhWorld; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition; import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.util.StringUtil; @@ -83,6 +84,7 @@ public class F3Screen { String r = MinecraftTextFormat.RED; String y = MinecraftTextFormat.YELLOW; + String a = MinecraftTextFormat.AQUA; String cf = MinecraftTextFormat.CLEAR_FORMATTING; @@ -123,6 +125,9 @@ public class F3Screen int posX = DhSectionPos.getX(sectionPos); int posZ = DhSectionPos.getZ(sectionPos); messageList.add("LOD Pos: "+y+detailLevel+"*"+posX+","+posZ+cf); + + AbstractDhRenderApiDefinition renderApiDef = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class); + messageList.add("Rendering API: "+a+renderApiDef.getApiName()+cf); } messageList.add(""); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/DhApiRenderProxy.java b/core/src/main/java/com/seibel/distanthorizons/core/render/DhApiRenderProxy.java index cab5d1a0c..8161540c4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/DhApiRenderProxy.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/DhApiRenderProxy.java @@ -85,13 +85,13 @@ public class DhApiRenderProxy implements IDhApiRenderProxy @Override public DhApiResult getDhDepthTextureId() { - int activeTexture = BlazeLodRenderer.INSTANCE.getActiveDepthTextureId(); + int activeTexture = -1;//DhTerrainShaderProgram.OpenGlRenderState.INSTANCE.getActiveDepthTextureId(); return (activeTexture == -1) ? DhApiResult.createFail("DH's depth texture hasn't been created and/or bound yet.", -1) : DhApiResult.createSuccess(activeTexture); } @Override public DhApiResult getDhColorTextureId() { - int activeTexture = BlazeLodRenderer.INSTANCE.getActiveColorTextureId(); + int activeTexture = -1;//DhTerrainShaderProgram.OpenGlRenderState.INSTANCE.getActiveColorTextureId(); return (activeTexture == -1) ? DhApiResult.createFail("DH's color texture hasn't been created and/or bound yet.", -1) : DhApiResult.createSuccess(activeTexture); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java index 1206c9e4b..92eaaeae8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderBufferHandler.java @@ -33,7 +33,7 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D; import com.seibel.distanthorizons.core.render.QuadTree.LodQuadTree; import com.seibel.distanthorizons.core.render.QuadTree.LodRenderSection; -import com.seibel.distanthorizons.core.render.renderer.BlazeLodRenderer; +import com.seibel.distanthorizons.core.render.renderer.LodRenderer; import com.seibel.distanthorizons.core.render.renderer.cullingFrustum.DhFrustumBounds; import com.seibel.distanthorizons.core.render.renderer.cullingFrustum.NeverCullFrustum; import com.seibel.distanthorizons.core.util.objects.SortedArraySet; @@ -48,7 +48,7 @@ import org.joml.Matrix4fc; import java.util.ArrayList; /** - * This object tells the {@link BlazeLodRenderer} what buffers to render + * This object tells the {@link LodRenderer} what buffers to render */ public class RenderBufferHandler implements AutoCloseable { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderParams.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderParams.java index 81ada6cbc..0f9f60e3b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderParams.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderParams.java @@ -45,7 +45,7 @@ public class RenderParams extends DhApiRenderParam /** @see DhRenderState#vanillaFogEnabled */ public boolean vanillaFogEnabled; - public boolean validationRun = false; + public boolean hasBeenValidated = false; @@ -120,7 +120,7 @@ public class RenderParams extends DhApiRenderParam { // Note: all strings here should be constants to prevent String allocations - this.validationRun = true; + this.hasBeenValidated = true; if (!MC_CLIENT.playerExists()) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderThreadTaskHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderThreadTaskHandler.java index dc068a552..a93f6a8b9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/RenderThreadTaskHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/RenderThreadTaskHandler.java @@ -104,7 +104,7 @@ public class RenderThreadTaskHandler { runnable.run(); - // only try running for 4ms (240 FPS) at a time to prevent random lag spikes + // only try running for a limited amount of time to prevent lag spikes long currentTimeMs = System.currentTimeMillis(); long runDuration = currentTimeMs - startTimeMs; if (runDuration > msMaxRunTime) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericRenderObjectFactory.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericRenderObjectFactory.java new file mode 100644 index 000000000..3e503fbb8 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericRenderObjectFactory.java @@ -0,0 +1,75 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.render.renderer; + +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderObjectFactory; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3d; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.logging.DhLogger; + +import java.util.List; +import java.util.*; + +/** + * Handles creating {@link DhApiRenderableBox}. + * + * @see IDhApiCustomRenderRegister + * @see DhApiRenderableBox + */ +public class GenericRenderObjectFactory implements IDhApiCustomRenderObjectFactory +{ + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + public static final GenericRenderObjectFactory INSTANCE = new GenericRenderObjectFactory(); + + + + //=============// + // constructor // + //=============// + + private GenericRenderObjectFactory() { } + + + + //================// + // group creation // + //================// + + @Override + public IDhApiRenderableBoxGroup createForSingleBox(String resourceLocation, DhApiRenderableBox box) + { + ArrayList list = new ArrayList<>(); + list.add(box); + return this.createAbsolutePositionedGroup(resourceLocation, list); + } + + @Override + public IDhApiRenderableBoxGroup createRelativePositionedGroup(String resourceLocation, DhApiVec3d originBlockPos, List boxList) + { return new RenderableBoxGroup(resourceLocation, new DhApiVec3d(originBlockPos.x, originBlockPos.y, originBlockPos.z), boxList, true); } + + @Override + public IDhApiRenderableBoxGroup createAbsolutePositionedGroup(String resourceLocation, List boxList) + { return new RenderableBoxGroup(resourceLocation, new DhApiVec3d(0, 0, 0), boxList, false); } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/BlazeLodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java similarity index 93% rename from core/src/main/java/com/seibel/distanthorizons/core/render/renderer/BlazeLodRenderer.java rename to core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index c3900521b..833d7dcc8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/BlazeLodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -39,7 +39,7 @@ import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; * This is where all the magic happens.
* This is where LODs are draw to the world. */ -public class BlazeLodRenderer +public class LodRenderer { public static final DhLogger LOGGER = new DhLoggerBuilder() .fileLevelConfig(Config.Common.Logging.logRendererEventToFile) @@ -52,19 +52,22 @@ public class BlazeLodRenderer private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); - public static final BlazeLodRenderer INSTANCE = new BlazeLodRenderer(); + public static final LodRenderer INSTANCE = new LodRenderer(); - private boolean renderObjectsCreated = false; + private boolean vanillaSettingsOverridden = false; //=============// // constructor // //=============// + //region - private BlazeLodRenderer() { } + private LodRenderer() { } + + //endregion @@ -105,7 +108,7 @@ public class BlazeLodRenderer boolean firstPass = !runningDeferredPass; // RenderParams parameter validation should be done before this - if (!renderParams.validationRun) + if (!renderParams.hasBeenValidated) { throw new IllegalArgumentException("Render parameters validation"); } @@ -113,6 +116,11 @@ public class BlazeLodRenderer RenderBufferHandler renderBufferHandler = renderParams.renderBufferHandler; IDhGenericRenderer genericRenderer = renderParams.genericRenderer; + IDhTerrainRenderer lodRenderer = SingletonInjector.INSTANCE.get(IDhTerrainRenderer.class); + IDhSsaoRenderer ssaoRenderer = SingletonInjector.INSTANCE.get(IDhSsaoRenderer.class); + IDhFogRenderer fogRenderer = SingletonInjector.INSTANCE.get(IDhFogRenderer.class); + IDhFarFadeRenderer farFadeRenderer = SingletonInjector.INSTANCE.get(IDhFarFadeRenderer.class); + AbstractDebugWireframeRenderer debugWireframeRenderer = SingletonInjector.INSTANCE.get(AbstractDebugWireframeRenderer.class); //=================// @@ -122,7 +130,9 @@ public class BlazeLodRenderer ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderSetupEvent.class, renderParams); profiler.push("LOD GL setup"); - if (!this.renderObjectsCreated) + lodRenderer.runRenderPassSetup(renderParams); + + if (!this.vanillaSettingsOverridden) { // only do this once, that way they can still be reverted if desired if (Config.Client.Advanced.Graphics.overrideVanillaGraphicsSettings.get()) @@ -134,7 +144,7 @@ public class BlazeLodRenderer MC.disableFabulousTransparency(); } - this.renderObjectsCreated = true; + this.vanillaSettingsOverridden = true; } if (firstPass) @@ -144,12 +154,6 @@ public class BlazeLodRenderer renderBufferHandler.buildRenderList(renderParams); } - IDhTerrainRenderer lodRenderer = SingletonInjector.INSTANCE.get(IDhTerrainRenderer.class); - IDhSsaoRenderer ssaoRenderer = SingletonInjector.INSTANCE.get(IDhSsaoRenderer.class); - IDhFogRenderer fogRenderer = SingletonInjector.INSTANCE.get(IDhFogRenderer.class); - IDhFarFadeRenderer farFadeRenderer = SingletonInjector.INSTANCE.get(IDhFarFadeRenderer.class); - AbstractDebugWireframeRenderer debugWireframeRenderer = SingletonInjector.INSTANCE.get(AbstractDebugWireframeRenderer.class); - //===========// @@ -274,6 +278,8 @@ public class BlazeLodRenderer profiler.popPush("LOD cleanup"); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderCleanupEvent.class, renderParams); + lodRenderer.runRenderPassCleanup(renderParams); + // end of internal LOD profiling @@ -310,22 +316,4 @@ public class BlazeLodRenderer - //===============// - // API functions // - //===============// - //region - - /** @return -1 if no frame buffer has been bound yet */ - public int getActiveFramebufferId() { return -1; } - - /** @return -1 if no texture has been bound yet */ - public int getActiveColorTextureId() { return -1; } - - /** @return -1 if no texture has been bound yet */ - public int getActiveDepthTextureId() { return -1; } - - //endregion - - - } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/RenderableBoxGroup.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/RenderableBoxGroup.java new file mode 100644 index 000000000..d935949cc --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/RenderableBoxGroup.java @@ -0,0 +1,361 @@ +package com.seibel.distanthorizons.core.render.renderer; + +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3d; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker; +import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer; +import org.jetbrains.annotations.Nullable; + +import java.io.Closeable; +import java.util.*; +import java.util.List; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +public class RenderableBoxGroup + extends AbstractList + implements IDhApiRenderableBoxGroup, Closeable +{ + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class); + + public static final AtomicInteger NEXT_ID_ATOMIC_INT = new AtomicInteger(0); + + + + public final long id; + + public final String resourceLocationNamespace; + public final String resourceLocationPath; + + /** If false the boxes will be positioned relative to the level's origin */ + public final boolean positionBoxesRelativeToGroupOrigin; + + private final List boxList; + /** backup list which allows for uploading the boxes even it the main list is being modified on a different thread. */ + private final List uploadBoxList; + private final DhApiVec3d originBlockPos; + + + public boolean active = true; + public boolean ssaoEnabled = true; + private boolean vertexDataDirty = true; + + public byte skyLight = LodUtil.MAX_MC_LIGHT; + public byte blockLight = LodUtil.MIN_MC_LIGHT; + public DhApiRenderableBoxGroupShading shading = DhApiRenderableBoxGroupShading.getDefaultShaded(); + + @Nullable + public Consumer beforeRenderFunc; + public Consumer afterRenderFunc; + + // instance data + public IDhGenericObjectVertexBufferContainer vertexBufferContainer = WRAPPER_FACTORY.createGenericObjectVboContainer(); + /** double buffering for thread safety and to prevent locking the render thread during update */ + private IDhGenericObjectVertexBufferContainer altVertexBufferContainer = WRAPPER_FACTORY.createGenericObjectVboContainer(); + + + + //=================// + // getters/setters // + //=================// + //region + + @Override + public long getId() { return this.id; } + + @Override + public String getResourceLocationNamespace() { return this.resourceLocationNamespace; } + @Override + public String getResourceLocationPath() { return this.resourceLocationPath; } + + @Override + public void setOriginBlockPos(DhApiVec3d pos) + { + this.originBlockPos.x = pos.x; + this.originBlockPos.y = pos.y; + this.originBlockPos.z = pos.z; + } + + @Override + public DhApiVec3d getOriginBlockPos() { return new DhApiVec3d(this.originBlockPos.x, this.originBlockPos.y, this.originBlockPos.z); } + + + @Override + public void setSkyLight(int skyLight) + { + if (skyLight < LodUtil.MIN_MC_LIGHT + || skyLight > LodUtil.MAX_MC_LIGHT) + { + throw new IllegalArgumentException("Sky light ["+skyLight+"] must be between ["+LodUtil.MIN_MC_LIGHT+"] and ["+LodUtil.MAX_MC_LIGHT+"] (inclusive)."); + } + this.skyLight = (byte)skyLight; + } + @Override + public int getSkyLight() { return this.skyLight; } + + @Override + public void setBlockLight(int blockLight) + { + if (blockLight < LodUtil.MIN_MC_LIGHT + || blockLight > LodUtil.MAX_MC_LIGHT) + { + throw new IllegalArgumentException("Block light ["+blockLight+"] must be between ["+LodUtil.MIN_MC_LIGHT+"] and ["+LodUtil.MAX_MC_LIGHT+"] (inclusive)."); + } + this.blockLight = (byte)blockLight; + } + @Override + public int getBlockLight() { return this.blockLight; } + + @Override + public void setPreRenderFunc(Consumer func) { this.beforeRenderFunc = func; } + + @Override + public void setPostRenderFunc(Consumer func) { this.afterRenderFunc = func; } + + @Override + public void setActive(boolean active) { this.active = active; } + @Override + public boolean isActive() { return this.active; } + + @Override + public void setSsaoEnabled(boolean ssaoEnabled) { this.ssaoEnabled = ssaoEnabled; } + @Override + public boolean isSsaoEnabled() { return this.ssaoEnabled; } + + @Override + public void setShading(DhApiRenderableBoxGroupShading shading) { this.shading = shading; } + @Override + public DhApiRenderableBoxGroupShading getShading() { return this.shading; } + + //endregion + + + + //=============// + // constructor // + //=============// + //region + + public RenderableBoxGroup( + String resourceLocation, + DhApiVec3d originBlockPos, List boxList, + boolean positionBoxesRelativeToGroupOrigin) throws IllegalArgumentException + { + String[] splitResourceLocation = resourceLocation.split(":"); + if (splitResourceLocation.length != 2) + { + throw new IllegalArgumentException("Resource Location must be a string that's separated by a single colon, for example: [DistantHorizons:Beacons], your namespace ["+resourceLocation+"], contains ["+(splitResourceLocation.length-1)+"] colons."); + } + + this.resourceLocationNamespace = splitResourceLocation[0]; + this.resourceLocationPath = splitResourceLocation[1]; + + this.id = NEXT_ID_ATOMIC_INT.getAndIncrement(); + this.boxList = Collections.synchronizedList(new ArrayList<>(boxList)); + this.uploadBoxList = Collections.synchronizedList(new ArrayList<>(boxList)); + + this.originBlockPos = originBlockPos; + this.positionBoxesRelativeToGroupOrigin = positionBoxesRelativeToGroupOrigin; + } + + //endregion + + + + //=================// + // render building // + //=================// + //region + + @Override + public void triggerBoxChange() { this.vertexDataDirty = true; } + + /** + * Does nothing if the vertex data is already up-to-date + * and is meaningless if using direct rendering. + */ + public void tryUpdateInstancedDataAsync() + { + // if the alt container is done, swap it in + if (this.altVertexBufferContainer.getState() == IDhGenericObjectVertexBufferContainer.EState.READY_TO_UPLOAD) + { + this.altVertexBufferContainer.uploadDataToGpu(); + + // swap VBO references for rendering + IDhGenericObjectVertexBufferContainer temp = this.vertexBufferContainer; + this.vertexBufferContainer = this.altVertexBufferContainer; + this.altVertexBufferContainer = temp; + + this.vertexDataDirty = false; + + return; + } + + + + // if the vertex data is already up to date, do nothing + if (!this.vertexDataDirty) + { + return; + } + + PriorityTaskPicker.Executor executor = ThreadPoolUtil.getRenderLoadingExecutor(); + if (executor == null || executor.isTerminated()) + { + return; + } + + // if the alternate container is already updating, don't double-queue it + if (this.altVertexBufferContainer.getState() == IDhGenericObjectVertexBufferContainer.EState.UPDATING_DATA) + { + return; + } + this.altVertexBufferContainer.setState(IDhGenericObjectVertexBufferContainer.EState.UPDATING_DATA); + + + + //this.altInstancedVbos.tryRunRenderThreadSetup(); + + // copy over the box list so we can upload without concurrent modification issues + this.uploadBoxList.clear(); + synchronized (this.uploadBoxList) + { + this.uploadBoxList.addAll(this.boxList); + } + + try + { + executor.runTask(() -> + { + try + { + this.altVertexBufferContainer.updateVertexData(this.uploadBoxList); + } + catch (Exception e) + { + LOGGER.error("Unexpected error updating instanced VBO data for: ["+this+"], error: ["+e.getMessage()+"].", e); + this.altVertexBufferContainer.setState(IDhGenericObjectVertexBufferContainer.EState.ERROR); + } + }); + } + catch (RejectedExecutionException ignore) + { + // the executor was shut down, it should be back up shortly and able to accept new jobs + this.altVertexBufferContainer.setState(IDhGenericObjectVertexBufferContainer.EState.NEW); + } + } + + //endregion + + + + //===============// + // render events // + //===============// + //region + + /** + * This is called before every frame, even if {@link this#isActive()} returns false.
+ * {@link this#isActive()} can be changed at this point before the object is rendered to the frame. + */ + public void preRender(DhApiRenderParam renderEventParam) + { + if (this.beforeRenderFunc != null) + { + this.beforeRenderFunc.accept(renderEventParam); + } + } + /** + * Called after rendering is completed.
+ * Can be used to handle any necessary cleanup. + */ + public void postRender(DhApiRenderParam renderEventParam) + { + if (this.afterRenderFunc != null) + { + this.afterRenderFunc.accept(renderEventParam); + } + } + + //endregion + + + + //================// + // List Overrides // + //================// + //region + + @Override + public boolean add(DhApiRenderableBox box) { return this.boxList.add(box); } + @Override + public DhApiRenderableBox get(int index) { return this.boxList.get(index); } + @Override + public int size() { return this.boxList.size(); } + @Override + public boolean removeIf(Predicate filter) { return this.boxList.removeIf(filter); } + @Override + public boolean remove(Object obj) { return this.boxList.remove(obj); } + @Override + public DhApiRenderableBox remove(int index) { return this.boxList.remove(index); } + @Override + public void replaceAll(UnaryOperator operator) { this.boxList.replaceAll(operator); } + @Override + public void sort(Comparator comparator) { this.boxList.sort(comparator); } + @Override + public void forEach(Consumer action) { this.boxList.forEach(action); } + @Override + public Spliterator spliterator() { return this.boxList.spliterator(); } + @Override + public Stream stream() { return this.boxList.stream(); } + @Override + public Stream parallelStream() { return this.boxList.parallelStream(); } + @Override + public void clear() { this.boxList.clear(); } + + //endregion + + + + //================// + // base overrides // + //================// + //region + + @Override + public String toString() { return "["+this.resourceLocationNamespace+":"+this.resourceLocationPath+"] ID:["+this.id+"], pos:[("+this.originBlockPos.x+", "+this.originBlockPos.y+", "+this.originBlockPos.z+")], size:["+this.size()+"], active:["+this.active+"]"; } + + @Override + public void close() + { + RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread(() -> + { + this.vertexBufferContainer.close(); + this.altVertexBufferContainer.close(); + }); + } + + //endregion + + + +} + \ No newline at end of file diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/AbstractDhRenderApiDefinition.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/AbstractDhRenderApiDefinition.java index 97de9cd2f..13f573fa6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/AbstractDhRenderApiDefinition.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/AbstractDhRenderApiDefinition.java @@ -10,6 +10,18 @@ import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindab public abstract class AbstractDhRenderApiDefinition implements IBindable { + //=========// + // getters // + //=========// + //region + + /** Used for debugging */ + public abstract String getApiName(); + + //endregion + + + //============// // singletons // //============// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/renderPass/IDhTerrainRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/renderPass/IDhTerrainRenderer.java index 146b4b477..ec5cb9119 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/renderPass/IDhTerrainRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/render/renderPass/IDhTerrainRenderer.java @@ -32,10 +32,10 @@ public interface IDhTerrainRenderer extends IBindable SortedArraySet bufferContainers, IProfilerWrapper profiler); - @Deprecated // TODO put somewhere else - int getVertexByteSize(); // TODO should these go somewhere else? + void runRenderPassSetup(RenderParams renderParams); + void runRenderPassCleanup(RenderParams renderParams); void applyToMcTexture(); void clearDepth(); void clearColor(); diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index d86891dbe..4a885828b 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -418,7 +418,7 @@ "distanthorizons.config.client.advanced.graphics.experimental.renderingApi": "Rendering API", "distanthorizons.config.client.advanced.graphics.experimental.renderingApi.@tooltip": - "", + "Requires a restart to change.", @@ -1044,7 +1044,7 @@ "distanthorizons.config.enum.EDhApiRendererMode.DEFAULT": "Default", "distanthorizons.config.enum.EDhApiRendererMode.DEBUG": - "Debug", + "Debug Triangle", "distanthorizons.config.enum.EDhApiRendererMode.DISABLED": "Disabled", @@ -1121,6 +1121,15 @@ "distanthorizons.config.enum.EDhApiGrassSideRendering.FADE_TO_DIRT": "Fade To Dirt", "distanthorizons.config.enum.EDhApiGrassSideRendering.AS_DIRT": - "As Dirt" + "As Dirt", + + "distanthorizons.config.enum.EDhApiRenderApi.AUTO": + "Auto", + "distanthorizons.config.enum.EDhApiRenderApi.OPEN_GL": + "OpenGL", + "distanthorizons.config.enum.EDhApiRenderApi.BLAZE_3D": + "Blaze3D" + + } diff --git a/core/src/main/resources/shaders/standard.vert b/core/src/main/resources/shaders/standard.vert index 86393a15e..1117af78e 100644 --- a/core/src/main/resources/shaders/standard.vert +++ b/core/src/main/resources/shaders/standard.vert @@ -68,7 +68,7 @@ void main() uint lights = meta & 0xFFu; float skyLight = (float(lights/16u)+0.5) / 16.0; float blockLight = (mod(float(lights), 16.0)+0.5) / 16.0; - vertexColor = vec4(1.0); //vec4(texture(uLightMap, vec2(skyLight, blockLight)).xyz, 1.0); + vertexColor = vec4(texture(uLightMap, vec2(skyLight, blockLight)).xyz, 1.0); if (!uIsWhiteWorld) {