Renderer rework completed
The renderer rework is done. Fixed some non-issues and optimized away some bind() calls. Also added some FIXME comments to some place that I noticed needs to be fixed.
This commit is contained in:
@@ -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);
|
||||
|
||||
+4
-8
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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!");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<numberOfBindingPoints; i++)
|
||||
GL43.glBindVertexBuffer(i, buffer, 0, strideSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
// Requires VertexAttribute binded, VertexBuffer binded
|
||||
public void bindBufferToBindingPoint(int buffer, int bindingPoint) {
|
||||
GL43.glBindVertexBuffer(bindingPoint, buffer, 0, strideSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindBufferFromAllBindingPoint() {
|
||||
// Requires VertexAttribute binded
|
||||
public void unbindBuffersFromAllBindingPoint() {
|
||||
for (int i=0; i<numberOfBindingPoints; i++)
|
||||
GL43.glBindVertexBuffer(i, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindBufferFromBindingPoint(int bindingPoint) {
|
||||
// Requires VertexAttribute binded
|
||||
public void unbindBuffersFromBindingPoint(int bindingPoint) {
|
||||
GL43.glBindVertexBuffer(bindingPoint, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
// Requires VertexAttribute binded
|
||||
public void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute) {
|
||||
GL43.glVertexAttribFormat(attributeIndex, attribute.elementCount, attribute.glType,
|
||||
attribute.normalized, strideSize); // Here strideSize is new attrib offset
|
||||
@@ -57,6 +63,7 @@ public final class VertexAttributePostGL43 extends VertexAttribute {
|
||||
}
|
||||
|
||||
@Override
|
||||
// Requires VertexAttribute binded
|
||||
public void completeAndCheck(int expectedStrideSize) {
|
||||
if (strideSize != expectedStrideSize) {
|
||||
ClientApi.LOGGER.error("Vertex Attribute calculated stride size " + strideSize +
|
||||
|
||||
@@ -22,17 +22,17 @@ public final class VertexAttributePreGL43 extends VertexAttribute {
|
||||
|
||||
TreeMap<Integer, TreeSet<Integer>> bindingPointsToIndexBuilder;
|
||||
ArrayList<VertexPointer> pointersBuilder;
|
||||
|
||||
|
||||
// This will bind VertexAttribute
|
||||
public VertexAttributePreGL43() {
|
||||
super();
|
||||
super(); // also bind VertexAttribute
|
||||
bindingPointsToIndexBuilder = new TreeMap<Integer, TreeSet<Integer>>();
|
||||
pointersBuilder = new ArrayList<VertexPointer>();
|
||||
}
|
||||
|
||||
@Override
|
||||
// Requires VertexAttribute binded, VertexBuffer binded
|
||||
public void bindBufferToAllBindingPoint(int buffer) {
|
||||
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, buffer);
|
||||
|
||||
for (int i=0; i<pointers.length; i++)
|
||||
GL20.glEnableVertexAttribArray(i);
|
||||
|
||||
@@ -45,10 +45,8 @@ public final class VertexAttributePreGL43 extends VertexAttribute {
|
||||
}
|
||||
|
||||
@Override
|
||||
// Requires VertexAttribute binded, VertexBuffer binded
|
||||
public void bindBufferToBindingPoint(int buffer, int bindingPoint) {
|
||||
|
||||
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, buffer);
|
||||
|
||||
int[] toBind = bindingPointsToIndex[bindingPoint];
|
||||
|
||||
for (int i=0; i<toBind.length; i++)
|
||||
@@ -63,13 +61,15 @@ public final class VertexAttributePreGL43 extends VertexAttribute {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void unbindBufferFromAllBindingPoint() {
|
||||
// Requires VertexAttribute binded
|
||||
public void unbindBuffersFromAllBindingPoint() {
|
||||
for (int i=0; i<pointers.length; i++)
|
||||
GL20.glDisableVertexAttribArray(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindBufferFromBindingPoint(int bindingPoint) {
|
||||
// Requires VertexAttribute binded
|
||||
public void unbindBuffersFromBindingPoint(int bindingPoint) {
|
||||
int[] toBind = bindingPointsToIndex[bindingPoint];
|
||||
|
||||
for (int i=0; i<toBind.length; i++)
|
||||
@@ -77,6 +77,7 @@ public final class VertexAttributePreGL43 extends VertexAttribute {
|
||||
}
|
||||
|
||||
@Override
|
||||
// Requires VertexAttribute binded
|
||||
public void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute) {
|
||||
TreeSet<Integer> 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+", "+
|
||||
|
||||
+6
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user