diff --git a/src/main/java/com/seibel/lod/core/api/EventApi.java b/src/main/java/com/seibel/lod/core/api/EventApi.java index bf6b49992..0930c48ac 100644 --- a/src/main/java/com/seibel/lod/core/api/EventApi.java +++ b/src/main/java/com/seibel/lod/core/api/EventApi.java @@ -160,8 +160,8 @@ public class EventApi // prevent issues related to the buffer builder // breaking or retaining previous data when changing worlds. - ClientApi.renderer.markForCleanup(); ClientApi.renderer.destroyBuffers(); + ClientApi.renderer.requestCleanup(); recalculateWidths = true; // TODO: Check if after the refactoring, is this still needed ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilderFactory); diff --git a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java index f2a8a746d..cbaa89e76 100644 --- a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java +++ b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java @@ -316,6 +316,8 @@ public class LodBufferBuilderFactory // keep a local version, so we don't have to worry about indexOutOfBounds Exceptions // if it changes in the LodRenderer while we are working here + // FIXME: THIS IS NOT HOW IT WORKS! We also can't just loop and copy it. Think of an + // idea to fix this! boolean[][] vanillaRenderedChunks = renderer.vanillaRenderedChunks; short gameChunkRenderDistance = (short) (vanillaRenderedChunks.length / 2 - 1); @@ -331,6 +333,7 @@ public class LodBufferBuilderFactory int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkX; int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkZ; + // FIXME: We don't need to ignore rendered chunks! Just build it and leave it for the renderer to decide! //We don't want to render this fake block if //The block is inside the render distance with, is not bigger than a chunk and is positioned in a chunk set as vanilla rendered // @@ -796,14 +799,7 @@ public class LodBufferBuilderFactory glProxy.setGlContext(GLProxyContext.LOD_BUILDER); // determine the upload method - GpuUploadMethod uploadMethod = CONFIG.client().advanced().buffers().getGpuUploadMethod(); - if (!glProxy.bufferStorageSupported && uploadMethod == GpuUploadMethod.BUFFER_STORAGE) - { - // if buffer storage isn't supported - // default to SUB_DATA - CONFIG.client().advanced().buffers().setGpuUploadMethod(GpuUploadMethod.SUB_DATA); - uploadMethod = GpuUploadMethod.SUB_DATA; - } + GpuUploadMethod uploadMethod = glProxy.getGpuUploadMethod(); // determine the upload timeout int uploadTimeoutInMS = CONFIG.client().advanced().buffers().getGpuUploadTimeoutInMilliseconds(); diff --git a/src/main/java/com/seibel/lod/core/render/GLProxy.java b/src/main/java/com/seibel/lod/core/render/GLProxy.java index 201782071..133c2a9dc 100644 --- a/src/main/java/com/seibel/lod/core/render/GLProxy.java +++ b/src/main/java/com/seibel/lod/core/render/GLProxy.java @@ -58,10 +58,10 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; public class GLProxy { private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class); - private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); private static final ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build()); - + + private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); private static GLProxy instance = null; @@ -80,13 +80,20 @@ public class GLProxy /** the proxyWorker's GL capabilities */ public final GLCapabilities proxyWorkerGlCapabilities; - /** Requires OpenGL 4.5, and offers the best buffer uploading */ + /** Requires OpenGL 4.4, and offers the best buffer uploading */ public final boolean bufferStorageSupported; - public final boolean openGL43VertexAttributeSupported; + /** Requires OpenGL 4.5 */ + public final boolean namedObjectSupported; + + /** Requires OpenGL 4.3 */ + public final boolean VertexAttributeBufferBindingSupported; - /** Requires OpenGL 3.0 */ - public final boolean mapBufferRangeSupported; + /** Requires OpenGL 3.0, which will current min requirement as 3.3, should always be true */ + @Deprecated + public final boolean mapBufferRangeSupported = true; + + private final GpuUploadMethod preferredUploadMethod; @@ -113,7 +120,15 @@ public class GLProxy // get Minecraft's context minecraftGlContext = GLFW.glfwGetCurrentContext(); minecraftGlCapabilities = GL.getCapabilities(); - + + // crash the game if the GPU doesn't support OpenGL 3.3 + if (!minecraftGlCapabilities.OpenGL33) + { + // Note: as of MC 1.17 this shouldn't happen since MC + // requires OpenGL 3.3, but for older MC version this will warn the player. + String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GLProxy.class.getSimpleName() + " and discovered this GPU doesn't support OpenGL 3.3 or greater."; + MC.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 3.3 or greater.")); + } // context creation setup GLFW.glfwDefaultWindowHints(); @@ -124,7 +139,6 @@ public class GLProxy // GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4); // GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 5); - // create the LodBuilder context lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, minecraftGlContext); GLFW.glfwMakeContextCurrent(lodBuilderGlContext); @@ -135,7 +149,12 @@ public class GLProxy proxyWorkerGlContext = GLFW.glfwCreateWindow(64, 48, "LOD proxy worker Window", 0L, minecraftGlContext); GLFW.glfwMakeContextCurrent(proxyWorkerGlContext); proxyWorkerGlCapabilities = GL.createCapabilities(); - + + // Check if we can use the make-over version of Vertex Attribute, which is available in GL4.3 or after + VertexAttributeBufferBindingSupported = minecraftGlCapabilities.glBindVertexBuffer != 0L; // Nullptr + + // Check if we can use the named version of all calls, which is available in GL4.5 or after + namedObjectSupported = minecraftGlCapabilities.glNamedBufferData != 0L; //Nullptr //==================================// // get any GPU related capabilities // @@ -145,66 +164,31 @@ public class GLProxy ClientApi.LOGGER.info("Lod Render OpenGL version [" + GL11.glGetString(GL11.GL_VERSION) + "]."); - // crash the game if the GPU doesn't support OpenGL 2.0 - if (!minecraftGlCapabilities.OpenGL20) - { - // Note: as of MC 1.17 this shouldn't happen since MC - // requires OpenGL 3.3, but just in case. - String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GLProxy.class.getSimpleName() + " and discoverd this GPU doesn't support OpenGL 2.0 or greater."; - MC.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 2.0 or greater.")); - } - - // Check if we can use the make-over version of Vertex Attribute, which is available in GL4.3 or after - openGL43VertexAttributeSupported = minecraftGlCapabilities.OpenGL43; // get specific capabilities - bufferStorageSupported = lodBuilderGlCapabilities.glBufferStorage != 0; - mapBufferRangeSupported = lodBuilderGlCapabilities.glMapBufferRange != 0; + // Check if we can use the Buffer Storage, which is available in GL4.4 or after + bufferStorageSupported = lodBuilderGlCapabilities.glBufferStorage != 0L; // Nullptr // display the capabilities if (!bufferStorageSupported) { - String fallBackVersion = mapBufferRangeSupported ? "3.0" : "1.5"; - ClientApi.LOGGER.warn("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance."); + ClientApi.LOGGER.warn("This GPU doesn't support Buffer Storage (OpenGL 4.4), falling back to using other methods."); } - - // if using AUTO gpuUpload - // determine a good default for the GPU - if (CONFIG.client().advanced().buffers().getGpuUploadMethod() == GpuUploadMethod.AUTO) + String vendor = GL15.glGetString(GL15.GL_VENDOR).toUpperCase(); // example return: "NVIDIA CORPORATION" + if (vendor.contains("NVIDIA") || vendor.contains("GEFORCE")) { - GpuUploadMethod uploadMethod; - String vendor = GL15.glGetString(GL15.GL_VENDOR).toUpperCase(); // example return: "NVIDIA CORPORATION" - if (vendor.contains("NVIDIA") || vendor.contains("GEFORCE")) - { - // NVIDIA card - - if (bufferStorageSupported) - { - uploadMethod = GpuUploadMethod.BUFFER_STORAGE; - } - else - { - uploadMethod = GpuUploadMethod.SUB_DATA; - } - } - else - { - // AMD or Intel card - - if (mapBufferRangeSupported) - { - uploadMethod = GpuUploadMethod.BUFFER_MAPPING; - } - else - { - uploadMethod = GpuUploadMethod.DATA; - } - } - - CONFIG.client().advanced().buffers().setGpuUploadMethod(uploadMethod); - ClientApi.LOGGER.info("GPU Vendor [" + vendor + "], Upload method set to [" + uploadMethod + "]."); + // NVIDIA card + preferredUploadMethod = bufferStorageSupported ? GpuUploadMethod.BUFFER_STORAGE : GpuUploadMethod.SUB_DATA; } + else + { + // AMD or Intel card + preferredUploadMethod = GpuUploadMethod.BUFFER_MAPPING; + } + + ClientApi.LOGGER.info("GPU Vendor [" + vendor + "], Preferred upload method is [" + preferredUploadMethod + "]."); + //==========// // clean up // //==========// @@ -296,6 +280,19 @@ public class GLProxy return instance; } + public GpuUploadMethod getGpuUploadMethod() { + GpuUploadMethod method = CONFIG.client().advanced().buffers().getGpuUploadMethod(); + + if (!bufferStorageSupported && method == GpuUploadMethod.BUFFER_STORAGE) + { + // if buffer storage isn't supported + // default to SUB_DATA + method = GpuUploadMethod.SUB_DATA; + } + + return method == GpuUploadMethod.AUTO ? preferredUploadMethod : method; + } + /** * Asynchronously calls the given runnable on proxy's OpenGL context. * Useful for creating/destroying OpenGL objects in a thread @@ -335,7 +332,7 @@ public class GLProxy * This only works with Legacy OpenGL because James hasn't * looking into a way for it to work with Modern OpenGL. */ - public void disableLegacyFog() + public boolean disableLegacyFog() { // make sure this is a legacy OpenGL context if (minecraftGlCapabilities.glFogf != 0) @@ -348,7 +345,9 @@ public class GLProxy GL11.glFogf(GL11.GL_FOG_START, 0.0f); GL11.glFogf(GL11.GL_FOG_END, Float.MAX_VALUE); GL11.glFogf(GL11.GL_FOG_DENSITY, 0.0f); + return true; } + return false; } diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java b/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java index 667a20d1b..5677c4cc0 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java @@ -61,12 +61,11 @@ public class LodRenderProgram extends ShaderProgram { public final int nearFogEndUniform; public final int farFogStartUniform; public final int farFogEndUniform; - + + // This will bind VertexAttribute public LodRenderProgram() { super(VERTEX_SHADER_PATH, FRAGMENT_SHADER_PATH, "fragColor"); - super.bind(); - posAttrib = getAttributeLocation("vPosition"); colAttrib = getAttributeLocation("color"); blockSkyLightAttrib = getAttributeLocation("blockSkyLight"); @@ -92,18 +91,16 @@ public class LodRenderProgram extends ShaderProgram { // TODO: Add better use of the LODFormat thing int vertexByteCount = LodUtil.LOD_VERTEX_FORMAT.getByteSize(); - if (GLProxy.getInstance().openGL43VertexAttributeSupported) - vao = new VertexAttributePostGL43(); + if (GLProxy.getInstance().VertexAttributeBufferBindingSupported) + vao = new VertexAttributePostGL43(); // also binds VertexAttribute else - vao = new VertexAttributePreGL43(); - vao.bind(); + vao = new VertexAttributePreGL43(); // also binds VertexAttribute + //vao.bind(); vao.setVertexAttribute(0, posAttrib, VertexAttribute.VertexPointer.addVec3Pointer(false)); vao.setVertexAttribute(0, colAttrib, VertexAttribute.VertexPointer.addUnsignedBytesPointer(4, true)); vao.setVertexAttribute(0, blockSkyLightAttrib, VertexAttribute.VertexPointer.addUnsignedBytePointer(false)); vao.setVertexAttribute(0, blockLightAttrib, VertexAttribute.VertexPointer.addUnsignedBytePointer(false)); vao.completeAndCheck(vertexByteCount); - //vao.unbind(); - //super.unbind(); } // Override ShaderProgram.bind() @@ -128,7 +125,7 @@ public class LodRenderProgram extends ShaderProgram { } public void unbindVertexBuffer() { - vao.unbindBufferFromAllBindingPoint(); + vao.unbindBuffersFromAllBindingPoint(); } public void fillUniformData(Mat4f modelViewMatrix, Mat4f projectionMatrix, Vec3f cameraPos, Color fogColor, int skyLight, int lightmapBindPoint) { diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index 58baefc51..22b80020f 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -22,9 +22,7 @@ package com.seibel.lod.core.render; import java.awt.Color; import java.util.HashSet; -import org.lwjgl.opengl.GL15; -import org.lwjgl.opengl.GL20; -import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL33; import com.seibel.lod.core.api.ApiShared; import com.seibel.lod.core.api.ClientApi; @@ -34,7 +32,6 @@ import com.seibel.lod.core.enums.config.GpuUploadMethod; import com.seibel.lod.core.enums.rendering.DebugMode; import com.seibel.lod.core.enums.rendering.FogColorMode; import com.seibel.lod.core.enums.rendering.FogDistance; -import com.seibel.lod.core.enums.rendering.FogDrawMode; import com.seibel.lod.core.handlers.IReflectionHandler; import com.seibel.lod.core.objects.lod.LodDimension; import com.seibel.lod.core.objects.math.Mat4f; @@ -74,7 +71,6 @@ public class LodRenderer // This tells us if the renderer is enabled or not. If in a world, it should be enabled. private boolean isSetupComplete = false; - private volatile boolean markToCleanup = false; /** This is used to generate the buildable buffers */ private final LodBufferBuilderFactory lodBufferBuilderFactory; @@ -90,7 +86,6 @@ public class LodRenderer // The shader program LodRenderProgram shaderProgram = null; - LightmapTexture lightmapTexture = null; private int vbosCenterX = 0; private int vbosCenterZ = 0; @@ -114,6 +109,7 @@ public class LodRenderer */ private volatile boolean partialRegen = false; private volatile boolean fullRegen = true; + private volatile boolean markToCleanup = false; /** * This HashSet contains every chunk that Vanilla Minecraft @@ -122,20 +118,16 @@ public class LodRenderer public boolean[][] vanillaRenderedChunks; public boolean vanillaRenderedChunksChanged; public boolean vanillaRenderedChunksEmptySkip = false; + + private boolean canVanillaFogBeDisabled = true; + public void requestCleanup() {markToCleanup = true;} public LodRenderer(LodBufferBuilderFactory newLodNodeBufferBuilder) { lodBufferBuilderFactory = newLodNodeBufferBuilder; } - public void markForCleanup() { - markToCleanup = true; - } - - - private LodDimension lastLodDimension = null; - /** * Besides drawing the LODs this method also starts * the async process of generating the Buffers that hold those LODs. @@ -167,10 +159,14 @@ public class LodRenderer return; } + // get MC's shader program + int currentProgram = GL33.glGetInteger(GL33.GL_CURRENT_PROGRAM); + GLProxy glProxy = GLProxy.getInstance(); - if (CONFIG.client().graphics().fogQuality().getDisableVanillaFog()) - glProxy.disableLegacyFog(); - + if (canVanillaFogBeDisabled && CONFIG.client().graphics().fogQuality().getDisableVanillaFog()) + if (!glProxy.disableLegacyFog()) + if (!MC_RENDER.tryDisableVanillaFog()) + canVanillaFogBeDisabled = false; // TODO move the buffer regeneration logic into its own class (probably called in the client api instead) // starting here... @@ -214,11 +210,9 @@ public class LodRenderer // FIXME: Currently, we check for last Lod Dimension so that we can trigger a cleanup() if dimension has changed // The better thing to do is to call cleanup() on leaving dimensions in the EventApi, but only for client-side. - if (markToCleanup || (lastLodDimension != null && lodDim != lastLodDimension)) { + if (markToCleanup) { markToCleanup = false; cleanup(); // This will unset the isSetupComplete, causing a setup() call. - lastLodDimension = lodDim; - //fullRegen = true; } //===================// @@ -227,28 +221,32 @@ public class LodRenderer profiler.push("LOD draw setup"); - int currentProgram = GL20.glGetInteger(GL20.GL_CURRENT_PROGRAM); - - // Setup LodRenderProgram and the LightmapTexture if it has not yet been done - if (!isSetupComplete) setup(); - - + /*---------Set GL State--------*/ // set the required open GL settings - if (CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_DETAIL_WIREFRAME) - GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_LINE); + GL33.glPolygonMode(GL33.GL_FRONT_AND_BACK, GL33.GL_LINE); else - GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL); - - GL15.glEnable(GL15.GL_CULL_FACE); - GL15.glEnable(GL15.GL_DEPTH_TEST); + GL33.glPolygonMode(GL33.GL_FRONT_AND_BACK, GL33.GL_FILL); + + GL33.glEnable(GL33.GL_CULL_FACE); + GL33.glEnable(GL33.GL_DEPTH_TEST); // enable transparent rendering - GL15.glBlendFunc(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA); - GL15.glEnable(GL15.GL_BLEND); + GL33.glBlendFunc(GL33.GL_SRC_ALPHA, GL33.GL_ONE_MINUS_SRC_ALPHA); + GL33.glEnable(GL33.GL_BLEND); - // get MC's shader program + /*---------Bind required objects--------*/ + // Setup LodRenderProgram and the LightmapTexture if it has not yet been done + // also binds LightmapTexture, VAO, and ShaderProgram + if (!isSetupComplete) { + setup(); + } else { + shaderProgram.bind(); + } + GL33.glActiveTexture(GL33.GL_TEXTURE0); + LightmapTexture lightmapTexture = new LightmapTexture(); + /*---------Get required data--------*/ // Get the matrixs for rendering Mat4f modelViewMatrix = translateModelViewMatrix(mcModelViewMatrix, partialTicks); int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH; @@ -258,28 +256,17 @@ public class LodRenderer farPlaneBlockDistance = Math.min(CONFIG.client().graphics().quality().getLodChunkRenderDistance(), LodUtil.CEILED_DIMENSION_MAX_RENDER_DISTANCE) * LodUtil.CHUNK_WIDTH; else farPlaneBlockDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * LodUtil.CHUNK_WIDTH; - Mat4f projectionMatrix = createProjectionMatrix(mcProjectionMatrix, vanillaBlockRenderedDistance, farPlaneBlockDistance); LodFogConfig fogSettings = new LodFogConfig(CONFIG, REFLECTION_HANDLER, farPlaneBlockDistance, vanillaBlockRenderedDistance); - //==============// - // shader setup // - //==============// - - // Bind and update the lightmap data - GL20.glActiveTexture(GL20.GL_TEXTURE0); - - shaderProgram.bind(); - // Fill the uniform data. Note: GL_TEXTURE_2D == texture bindpoint 0 + /*---------Fill uniform data--------*/ + // Fill the uniform data. Note: GL33.GL_TEXTURE0 == texture bindpoint 0 shaderProgram.fillUniformData(modelViewMatrix, projectionMatrix, getTranslatedCameraPos(), getFogColor(), (int) (MC.getSkyDarken(partialTicks) * 15), 0); - - lightmapTexture = new LightmapTexture(); - lightmapTexture.bind(); - lightmapTexture.fillData(MC_RENDER.getLightmapTextureWidth(), MC_RENDER.getLightmapTextureHeight(), MC_RENDER.getLightmapPixels()); - // Previous guy said fog setting may be different from region to region, but the fogSettings never changed... soooooo... shaderProgram.fillUniformDataForFog(fogSettings); + // Note: Since lightmapTexture is changing every frame, it's faster to recreate it than to reuse the old one. + lightmapTexture.fillData(MC_RENDER.getLightmapTextureWidth(), MC_RENDER.getLightmapTextureHeight(), MC_RENDER.getLightmapPixels()); //===========// // rendering // @@ -288,7 +275,7 @@ public class LodRenderer profiler.popPush("LOD draw"); boolean cullingDisabled = CONFIG.client().graphics().advancedGraphics().getDisableDirectionalCulling(); - boolean renderBufferStorage = CONFIG.client().advanced().buffers().getGpuUploadMethod() == GpuUploadMethod.BUFFER_STORAGE && glProxy.bufferStorageSupported; + boolean usingBufferStorage = glProxy.getGpuUploadMethod() == GpuUploadMethod.BUFFER_STORAGE; // where the center of the buffers is (needed when culling regions) // render each of the buffers @@ -308,16 +295,12 @@ public class LodRenderer int bufferId = 0; for (int i = 0; i < vbos[x][z].length; i++) { - bufferId = (storageBufferIds != null && renderBufferStorage) ? storageBufferIds[x][z][i] : vbos[x][z][i].id; + bufferId = (storageBufferIds != null && usingBufferStorage) ? storageBufferIds[x][z][i] : vbos[x][z][i].id; if (bufferId==0) continue; - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferId); - shaderProgram.bind(); + GL33.glBindBuffer(GL33.GL_ARRAY_BUFFER, bufferId); shaderProgram.bindVertexBuffer(bufferId); - GL30.glDrawArrays(GL30.GL_TRIANGLES, 0, vbos[x][z][i].vertexCount); - //shaderProgram.unbindVertexBuffer(); - + GL33.glDrawArrays(GL33.GL_TRIANGLES, 0, vbos[x][z][i].vertexCount); } - } } } @@ -325,24 +308,23 @@ public class LodRenderer //================// // render cleanup // //================// - - // if this cleanup isn't done MC will crash - // when trying to render its own terrain - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); - - lightmapTexture.unbind(); - shaderProgram.unbind(); - lightmapTexture.free(); profiler.popPush("LOD cleanup"); - GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL); - GL15.glDisable(GL15.GL_BLEND); // TODO: what should this be reset to? + // if this cleanup isn't done MC will crash + // when trying to render its own terrain + GL33.glBindBuffer(GL33.GL_ARRAY_BUFFER, 0); + + shaderProgram.unbind(); + lightmapTexture.free(); + + GL33.glPolygonMode(GL33.GL_FRONT_AND_BACK, GL33.GL_FILL); + GL33.glDisable(GL33.GL_BLEND); // TODO: what should this be reset to? - GL20.glUseProgram(currentProgram); + GL33.glUseProgram(currentProgram); // clear the depth buffer so everything is drawn over the LODs - GL15.glClear(GL15.GL_DEPTH_BUFFER_BIT); + GL33.glClear(GL33.GL_DEPTH_BUFFER_BIT); // end of internal LOD profiling profiler.pop(); @@ -365,7 +347,6 @@ public class LodRenderer isSetupComplete = true; shaderProgram = new LodRenderProgram(); - //lightmapTexture = new LightmapTexture(); } /** Create all buffers that will be used. */ @@ -461,11 +442,7 @@ public class LodRenderer } isSetupComplete = false; ClientApi.LOGGER.info("Renderer Cleanup Started"); - //GLProxy.getInstance().setGlContext(GLProxyContext.LOD_BUILDER); - shaderProgram.free(); - //lightmapTexture.free(); - //GLProxy.getInstance().setGlContext(GLProxyContext.NONE); ClientApi.LOGGER.info("Renderer Cleanup Complete"); } @@ -554,46 +531,10 @@ public class LodRenderer prevPlayerPosTime = newTime; } - - /* - // determine how far the lighting has to - // change in order to rebuild the buffers - - // the max brightness is 1 and the minimum is 0.2 - float skyBrightness = lodDim.dimension.hasSkyLight() ? MC.getSkyDarken(partialTicks) : 0.2f; - float minLightingDifference; - switch (CONFIG.client().advanced().buffers().getRebuildTimes()) - { - case FREQUENT: - minLightingDifference = 0.025f; - break; - case NORMAL: - minLightingDifference = 0.05f; - break; - default: - case RARE: - minLightingDifference = 0.1f; - break; - } - - // check if the lighting changed - if (Math.abs(skyBrightness - prevSkyBrightness) > minLightingDifference - // make sure the lighting gets to the max/minimum value - // (just in case the minLightingDifference is too large to notice the change) - || (skyBrightness == 1.0f && prevSkyBrightness != 1.0f) // noon - || (skyBrightness == 0.2f && prevSkyBrightness != 0.2f) // midnight - || MC_RENDER.getGamma() != prevBrightness) - { - fullRegen = true; - prevBrightness = MC_RENDER.getGamma(); - prevSkyBrightness = skyBrightness; - }*/ - //================// // partial regens // //================// - // check if the vanilla rendered chunks changed if (newTime - prevVanillaChunkTime > CONFIG.client().advanced().buffers().getRebuildTimes().renderedChunkTimeout) { @@ -605,7 +546,6 @@ public class LodRenderer prevVanillaChunkTime = newTime; } - // check if there is any newly generated terrain to show if (newTime - prevChunkTime > CONFIG.client().advanced().buffers().getRebuildTimes().chunkChangeTimeout) { @@ -617,8 +557,6 @@ public class LodRenderer prevChunkTime = newTime; } - - //==============// // LOD skipping // //==============// @@ -660,5 +598,5 @@ public class LodRenderer vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth]; } - + } diff --git a/src/main/java/com/seibel/lod/core/render/objects/LightmapTexture.java b/src/main/java/com/seibel/lod/core/render/objects/LightmapTexture.java index e6b2dcf1f..16494c204 100644 --- a/src/main/java/com/seibel/lod/core/render/objects/LightmapTexture.java +++ b/src/main/java/com/seibel/lod/core/render/objects/LightmapTexture.java @@ -3,12 +3,8 @@ package com.seibel.lod.core.render.objects; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; -import com.seibel.lod.core.util.SingletonHandler; -import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; - public class LightmapTexture { - private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class); - public final int id; + public int id; public LightmapTexture() { id = GL30.glGenTextures(); @@ -29,6 +25,9 @@ public class LightmapTexture { // private int[] testArray; public void fillData(int lightMapWidth, int lightMapHeight, int[] pixels) { + GL20.glDeleteTextures(id); + id = GL30.glGenTextures(); + GL20.glBindTexture(GL20.GL_TEXTURE_2D, id); if (pixels.length != lightMapWidth*lightMapHeight) throw new RuntimeException("Lightmap Width*Height not equal to pixels provided!"); diff --git a/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java b/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java index 5d82438da..b0490559f 100644 --- a/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java +++ b/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java @@ -23,7 +23,6 @@ import java.awt.Color; import java.nio.FloatBuffer; import org.lwjgl.opengl.GL20; -import org.lwjgl.opengl.GL30; import org.lwjgl.system.MemoryStack; import com.seibel.lod.core.objects.math.Mat4f; @@ -44,9 +43,10 @@ public class ShaderProgram { /** Stores the handle of the program. */ public final int id; - - /** Creates a shader program. */ - // FIXME: A better way to set the fragData output name + + // TODO: A better way to set the fragData output name + /** Creates a shader program. + * This will bind ShaderProgram */ public ShaderProgram(String vert, String frag, String fragDataOutputName) { Shader vertShader = new Shader(GL20.GL_VERTEX_SHADER, vert, false); @@ -68,13 +68,15 @@ public class ShaderProgram free(); // important! throw new RuntimeException(message); } + GL20.glUseProgram(id); // This HAVE to be a direct call to prevent calling the overloaded version } - /** Calls GL20.glUseProgram(this.id) */ + /** This will bind ShaderProgram */ public void bind() { GL20.glUseProgram(id); } + /** This will unbind ShaderProgram */ public void unbind() { GL20.glUseProgram(0); } @@ -114,33 +116,39 @@ public class ShaderProgram if (i==-1) throw new RuntimeException("Uniform name not found: "+name); return i; } - + + /** Requires ShaderProgram binded. */ public void setUniform(int location, boolean value) { // This use -1 for false as that equals all one set GL20.glUniform1i(location, value ? 1 : 0); } - + + /** Requires ShaderProgram binded. */ public void setUniform(int location, int value) { GL20.glUniform1i(location, value); } - + + /** Requires ShaderProgram binded. */ public void setUniform(int location, float value) { GL20.glUniform1f(location, value); } - + + /** Requires ShaderProgram binded. */ public void setUniform(int location, Vec3f value) { GL20.glUniform3f(location, value.x, value.y, value.z); } - + + /** Requires ShaderProgram binded. */ public void setUniform(int location, Vec3d value) { GL20.glUniform3f(location, (float) value.x, (float) value.y, (float) value.z); } - + + /** Requires ShaderProgram binded. */ public void setUniform(int location, Mat4f value) { try (MemoryStack stack = MemoryStack.stackPush()) @@ -151,7 +159,8 @@ public class ShaderProgram } } - /** Converts the color's RGBA values into values between 0 and 1. */ + /** Converts the color's RGBA values into values between 0 and 1. + * Requires ShaderProgram binded. */ public void setUniform(int location, Color value) { GL20.glUniform4f(location, value.getRed() / 256.0f, value.getGreen() / 256.0f, value.getBlue() / 256.0f, value.getAlpha() / 256.0f); diff --git a/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java b/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java index 8a72ccc63..241b3465f 100644 --- a/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java +++ b/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java @@ -23,8 +23,6 @@ import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; -import com.seibel.lod.core.api.ClientApi; - public abstract class VertexAttribute { public static final class VertexPointer { @@ -74,13 +72,18 @@ public abstract class VertexAttribute { /** Stores the handle of the VertexAttribute. */ public final int id; + // This will bind VertexAttribute protected VertexAttribute() { id = GL30.glGenVertexArrays(); + GL30.glBindVertexArray(id); } - + + // This will bind VertexAttribute public void bind() { GL30.glBindVertexArray(id); } + + // This will unbind VertexAttribute public void unbind() { GL30.glBindVertexArray(0); } @@ -90,16 +93,16 @@ public abstract class VertexAttribute { GL30.glDeleteVertexArrays(id); } - // Requires Vao binded + // Requires VertexAttribute binded, VertexBuffer binded public abstract void bindBufferToAllBindingPoint(int buffer); - // Requires Vao binded + // Requires VertexAttribute binded, VertexBuffer binded public abstract void bindBufferToBindingPoint(int buffer, int bindingPoint); - // Requires Vao binded - public abstract void unbindBufferFromAllBindingPoint(); - // Requires Vao binded - public abstract void unbindBufferFromBindingPoint(int bindingPoint); - // Requires Vao binded + // Requires VertexAttribute binded + public abstract void unbindBuffersFromAllBindingPoint(); + // Requires VertexAttribute binded + public abstract void unbindBuffersFromBindingPoint(int bindingPoint); + // Requires VertexAttribute binded public abstract void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute); - // Requires Vao binded + // Requires VertexAttribute binded public abstract void completeAndCheck(int expectedStrideSize); } diff --git a/src/main/java/com/seibel/lod/core/render/objects/VertexAttributePostGL43.java b/src/main/java/com/seibel/lod/core/render/objects/VertexAttributePostGL43.java index 9485e08e1..a8ec0da3a 100644 --- a/src/main/java/com/seibel/lod/core/render/objects/VertexAttributePostGL43.java +++ b/src/main/java/com/seibel/lod/core/render/objects/VertexAttributePostGL43.java @@ -19,34 +19,40 @@ public final class VertexAttributePostGL43 extends VertexAttribute { int numberOfBindingPoints = 0; int strideSize = 0; - + + // This will bind VertexAttribute public VertexAttributePostGL43() { - super(); + super(); // also bind VertexAttribute } @Override + // Requires VertexAttribute binded, VertexBuffer binded public void bindBufferToAllBindingPoint(int buffer) { for (int i=0; i> bindingPointsToIndexBuilder; ArrayList pointersBuilder; - + + // This will bind VertexAttribute public VertexAttributePreGL43() { - super(); + super(); // also bind VertexAttribute bindingPointsToIndexBuilder = new TreeMap>(); pointersBuilder = new ArrayList(); } @Override + // Requires VertexAttribute binded, VertexBuffer binded public void bindBufferToAllBindingPoint(int buffer) { - GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, buffer); - for (int i=0; i intArray = bindingPointsToIndexBuilder.get(bindingPoint); if (intArray == null) { @@ -94,6 +95,7 @@ public final class VertexAttributePreGL43 extends VertexAttribute { } @Override + // Requires VertexAttribute binded public void completeAndCheck(int expectedStrideSize) { int maxBindPointNumber = bindingPointsToIndexBuilder.lastKey(); bindingPointsToIndex = new int[maxBindPointNumber+1][]; @@ -106,7 +108,6 @@ public final class VertexAttributePreGL43 extends VertexAttribute { } }); - pointers = pointersBuilder.toArray(new VertexPointer[pointersBuilder.size()]); pointersOffset = new int[pointers.length]; pointersBuilder = null; // Release the builder @@ -131,11 +132,12 @@ public final class VertexAttributePreGL43 extends VertexAttribute { // Debug logging ClientApi.LOGGER.info("Vertex Attribute Debug Data:"); + ClientApi.LOGGER.info("AttributeIndex: ElementCount, glType, normalized, strideSize, offset"); for (int i=0; i< pointers.length; i++) { VertexPointer pointer = pointers[i]; if (pointer==null) { - ClientApi.LOGGER.info(i + ": Null"); + ClientApi.LOGGER.warn(i + ": Null!!!!"); continue; } ClientApi.LOGGER.info(i + ": "+pointer.elementCount+", "+ diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java index daa97807f..982b02a89 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java @@ -125,4 +125,10 @@ public interface IMinecraftRenderWrapper int getLightmapTextureWidth(); /** @returns -1 if there was an issue getting the lightmap */ public int getLightmapGLFormat(); + + /** Try and disable vanilla fog. Return true if successful, or false if not able to. + * If we are still using legacy fog, this method will not be called. */ + public default boolean tryDisableVanillaFog() { + return false; + } }