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 d5c9ea638..bf4455843 100644
--- a/src/main/java/com/seibel/lod/core/api/EventApi.java
+++ b/src/main/java/com/seibel/lod/core/api/EventApi.java
@@ -121,6 +121,7 @@ public class EventApi
{
// the player just unloaded a world/dimension
ThreadMapUtil.clearMaps();
+ ClientApi.renderer.markForCleanup();
new Thread(() -> checkIfDisconnectedFromServer()).start();
}
@@ -155,11 +156,12 @@ public class EventApi
// prevent issues related to the buffer builder
// breaking or retaining previous data when changing worlds.
+ ClientApi.renderer.markForCleanup();
ClientApi.renderer.destroyBuffers();
recalculateWidths = true;
+ // TODO: Check if after the refactoring, is this still needed
ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilderFactory);
-
// make sure the nulled objects are freed.
// (this prevents an out of memory error when
// changing worlds)
diff --git a/src/main/java/com/seibel/lod/core/objects/rending/LodFogConfig.java b/src/main/java/com/seibel/lod/core/objects/rending/LodFogConfig.java
deleted file mode 100644
index 0fcdba0db..000000000
--- a/src/main/java/com/seibel/lod/core/objects/rending/LodFogConfig.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This file is part of the Distant Horizon mod (formerly the LOD Mod),
- * licensed under the GNU GPL 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 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.seibel.lod.core.objects.rending;
-
-import com.seibel.lod.core.enums.rendering.FogDistance;
-import com.seibel.lod.core.enums.rendering.FogDrawMode;
-
-/**
- * This object is just a replacement for an array
- * to make things easier to understand in the LodRenderer.
- *
- * @author James Seibel
- * @version 11-26-2021
- */
-public class LodFogConfig
-{
- public FogDrawMode fogDrawMode;
- public FogDistance fogDistance;
-
-
- public float nearFogStart = 0;
- public float nearFogEnd = 0;
-
- public float farFogStart = 0;
- public float farFogEnd = 0;
-}
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 ee7aa0b0b..201782071 100644
--- a/src/main/java/com/seibel/lod/core/render/GLProxy.java
+++ b/src/main/java/com/seibel/lod/core/render/GLProxy.java
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
- * Copyright (C) 2020 James Seibel
+ * Copyright (C) 2021 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,8 +27,6 @@ import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
-import org.lwjgl.opengl.GL20;
-import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLCapabilities;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
@@ -36,8 +34,6 @@ import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.enums.rendering.GLProxyContext;
-import com.seibel.lod.core.render.shader.LodShader;
-import com.seibel.lod.core.render.shader.LodShaderProgram;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
@@ -84,19 +80,11 @@ public class GLProxy
/** the proxyWorker's GL capabilities */
public final GLCapabilities proxyWorkerGlCapabilities;
-
-
- /** This program contains all shaders required when rendering LODs */
- public LodShaderProgram lodShaderProgram;
- /** This is the VAO that is used when rendering */
- public final int vertexArrayObjectId;
- /** This is the 2D texture that holds MC's lightmap */
- public final int lightMapTextureId;
-
-
/** Requires OpenGL 4.5, and offers the best buffer uploading */
public final boolean bufferStorageSupported;
+ public final boolean openGL43VertexAttributeSupported;
+
/** Requires OpenGL 3.0 */
public final boolean mapBufferRangeSupported;
@@ -109,6 +97,8 @@ public class GLProxy
*/
private GLProxy()
{
+ // this must be created on minecraft's render context to work correctly
+
ClientApi.LOGGER.info("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error.");
// getting Minecraft's context has to be done on the render thread,
@@ -147,10 +137,6 @@ public class GLProxy
proxyWorkerGlCapabilities = GL.createCapabilities();
-
-
-
-
//==================================//
// get any GPU related capabilities //
//==================================//
@@ -168,7 +154,8 @@ public class GLProxy
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;
@@ -218,27 +205,6 @@ public class GLProxy
CONFIG.client().advanced().buffers().setGpuUploadMethod(uploadMethod);
ClientApi.LOGGER.info("GPU Vendor [" + vendor + "], Upload method set to [" + uploadMethod + "].");
}
-
-
-
-
- //==============//
- // shader setup //
- //==============//
-
- setGlContext(GLProxyContext.MINECRAFT);
-
- createShaderProgram();
-
- // Note: VAO objects can not be shared between contexts,
- // this must be created on minecraft's render context to work correctly
- vertexArrayObjectId = GL30.glGenVertexArrays();
-
- lightMapTextureId = GL30.glGenTextures();
-
-
-
-
//==========//
// clean up //
//==========//
@@ -246,53 +212,10 @@ public class GLProxy
// Since this is created on the render thread, make sure the Minecraft context is used in the end
setGlContext(GLProxyContext.MINECRAFT);
-
// GLProxy creation success
ClientApi.LOGGER.info(GLProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
}
- /**
- * Creates all required shaders
- * @throws RuntimeException
- * @throws FileNotFoundException
- */
- public void createShaderProgram()
- {
- LodShader vertexShader = null;
- LodShader fragmentShader = null;
-
- // get the shaders from the resource folder
- // Use File.separator ONLY if the file is external (not in the resourse), otherwise use "/"
- vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "shaders/standard.vert", false);
- fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "shaders/flat_shaded.frag", false);
-
- // this can be used when testing shaders,
- // since we can't hot swap the files in the resource folder
- // vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "C:/Users/James Seibel/Desktop/shaders/standard.vert", true);
- // fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "C:/Users/James Seibel/Desktop/shaders/flat_shaded.frag", true);
-
-
- // create the shaders
-
- lodShaderProgram = new LodShaderProgram();
-
- // Attach the compiled shaders to the program, throws RuntimeException on link error
- lodShaderProgram.attachShader(vertexShader);
- lodShaderProgram.attachShader(fragmentShader);
-
- // activate the fragment shader output
- GL30.glBindFragDataLocation(lodShaderProgram.id, 0, "fragColor");
-
- // attach the shader program to the OpenGL context
- lodShaderProgram.link();
-
- // after the shaders have been attached to the program
- // we don't need their OpenGL references anymore
- GL20.glDeleteShader(vertexShader.id);
- GL20.glDeleteShader(fragmentShader.id);
- }
-
-
/**
* A wrapper function to make switching contexts easier.
* Does nothing if the calling thread is already using newContext.
@@ -362,22 +285,17 @@ public class GLProxy
+ "no context [0].");
}
+ public static boolean hasInstance() {
+ return instance != null;
+ }
public static GLProxy getInstance()
{
if (instance == null)
instance = new GLProxy();
-
return instance;
}
-
-
-
-
-
-
-
/**
* Asynchronously calls the given runnable on proxy's OpenGL context.
* Useful for creating/destroying OpenGL objects in a thread
diff --git a/src/main/java/com/seibel/lod/core/render/LodFogConfig.java b/src/main/java/com/seibel/lod/core/render/LodFogConfig.java
new file mode 100644
index 000000000..7c2d2abe1
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/render/LodFogConfig.java
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the Distant Horizon mod (formerly the LOD Mod),
+ * licensed under the GNU GPL 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 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.core.render;
+
+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.wrapperInterfaces.config.ILodConfigWrapperSingleton;
+
+/**
+ * This object is just a replacement for an array
+ * to make things easier to understand in the LodRenderer.
+ *
+ * @author James Seibel
+ * @version 11-26-2021
+ */
+public class LodFogConfig
+{
+ public FogDrawMode fogDrawMode;
+ public FogDistance fogDistance;
+
+ public float nearFogStart = 0;
+ public float nearFogEnd = 0;
+
+ public float farFogStart = 0;
+ public float farFogEnd = 0;
+
+ public LodFogConfig(ILodConfigWrapperSingleton config, IReflectionHandler reflectionHandler, int farPlaneBlockDistance, int vanillaBlockRenderedDistance) {
+
+ fogDrawMode = config.client().graphics().fogQuality().getFogDrawMode();
+ if (fogDrawMode == FogDrawMode.USE_OPTIFINE_SETTING)
+ fogDrawMode = reflectionHandler.getFogDrawMode();
+
+ // how different distances are drawn depends on the quality set
+ fogDistance = config.client().graphics().fogQuality().getFogDistance();
+
+ // far fog //
+
+ if (config.client().graphics().fogQuality().getFogDistance() == FogDistance.NEAR_AND_FAR)
+ farFogStart = farPlaneBlockDistance * 0.9f;
+ else
+ // for more realistic fog when using FAR
+ farFogStart = Math.min(vanillaBlockRenderedDistance * 1.5f, farPlaneBlockDistance * 0.9f);
+
+ farFogEnd = farPlaneBlockDistance;
+
+
+ // near fog //
+
+ // the reason that I wrote fogEnd then fogStart backwards
+ // is because we are using fog backwards to how
+ // it is normally used, hiding near objects
+ // instead of far objects.
+ nearFogEnd = vanillaBlockRenderedDistance * 1.41f;
+ nearFogStart = vanillaBlockRenderedDistance * 1.6f;
+ }
+
+}
diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java b/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java
new file mode 100644
index 000000000..667a20d1b
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/render/LodRenderProgram.java
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the Distant Horizon mod (formerly the LOD Mod),
+ * licensed under the GNU GPL v3 License.
+ *
+ * Copyright (C) 2021 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.core.render;
+
+import java.awt.Color;
+
+import org.lwjgl.opengl.GL20;
+import org.lwjgl.opengl.GL42;
+import org.lwjgl.opengl.GL43;
+
+import com.seibel.lod.core.enums.rendering.FogDistance;
+import com.seibel.lod.core.enums.rendering.FogDrawMode;
+import com.seibel.lod.core.objects.math.Mat4f;
+import com.seibel.lod.core.objects.math.Vec3f;
+import com.seibel.lod.core.render.objects.ShaderProgram;
+import com.seibel.lod.core.render.objects.VertexAttribute;
+import com.seibel.lod.core.render.objects.VertexAttributePostGL43;
+import com.seibel.lod.core.render.objects.VertexAttributePreGL43;
+import com.seibel.lod.core.util.LodUtil;
+
+public class LodRenderProgram extends ShaderProgram {
+ public static final String VERTEX_SHADER_PATH = "shaders/standard.vert";
+ public static final String FRAGMENT_SHADER_PATH = "shaders/flat_shaded.frag";
+
+ public final VertexAttribute vao;
+
+ // Attributes
+ public final int posAttrib;
+ public final int colAttrib;
+ public final int blockSkyLightAttrib;
+ public final int blockLightAttrib;
+ // Uniforms
+ public final int mvmUniform;
+ public final int projUniform;
+ public final int cameraUniform;
+ public final int fogColorUniform;
+ // public final int skyLightUniform; worldSkyLight is currently not used
+ public final int lightMapUniform;
+ // Fog Uniforms
+ public final int fogEnabledUniform;
+ public final int nearFogEnabledUniform;
+ public final int farFogEnabledUniform;
+ public final int nearFogStartUniform;
+ public final int nearFogEndUniform;
+ public final int farFogStartUniform;
+ public final int farFogEndUniform;
+
+ public LodRenderProgram() {
+ super(VERTEX_SHADER_PATH, FRAGMENT_SHADER_PATH, "fragColor");
+
+ super.bind();
+
+ posAttrib = getAttributeLocation("vPosition");
+ colAttrib = getAttributeLocation("color");
+ blockSkyLightAttrib = getAttributeLocation("blockSkyLight");
+ blockLightAttrib = getAttributeLocation("blockLight");
+
+ mvmUniform = getUniformLocation("modelViewMatrix");
+ projUniform = getUniformLocation("projectionMatrix");
+ cameraUniform = getUniformLocation("cameraPos");
+ fogColorUniform = getUniformLocation("fogColor");
+ // skyLightUniform = getUniformLocation("worldSkyLight");
+ lightMapUniform = getUniformLocation("lightMap");
+
+ // Fog uniforms
+ fogEnabledUniform = getUniformLocation("fogEnabled");
+ nearFogEnabledUniform = getUniformLocation("nearFogEnabled");
+ farFogEnabledUniform = getUniformLocation("farFogEnabled");
+ // near
+ nearFogStartUniform = getUniformLocation("nearFogStart");
+ nearFogEndUniform = getUniformLocation("nearFogEnd");
+ // far
+ farFogStartUniform = getUniformLocation("farFogStart");
+ farFogEndUniform = getUniformLocation("farFogEnd");
+
+ // TODO: Add better use of the LODFormat thing
+ int vertexByteCount = LodUtil.LOD_VERTEX_FORMAT.getByteSize();
+ if (GLProxy.getInstance().openGL43VertexAttributeSupported)
+ vao = new VertexAttributePostGL43();
+ else
+ vao = new VertexAttributePreGL43();
+ 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()
+ public void bind() {
+ super.bind();
+ vao.bind();
+ }
+ // Override ShaderProgram.unbind()
+ public void unbind() {
+ super.unbind();
+ vao.unbind();
+ }
+
+ // Override ShaderProgram.free()
+ public void free() {
+ vao.free();
+ super.free();
+ }
+
+ public void bindVertexBuffer(int vbo) {
+ vao.bindBufferToAllBindingPoint(vbo);
+ }
+
+ public void unbindVertexBuffer() {
+ vao.unbindBufferFromAllBindingPoint();
+ }
+
+ public void fillUniformData(Mat4f modelViewMatrix, Mat4f projectionMatrix, Vec3f cameraPos, Color fogColor, int skyLight, int lightmapBindPoint) {
+ super.bind();
+ // uniforms
+ setUniform(mvmUniform, modelViewMatrix);
+ setUniform(projUniform, projectionMatrix);
+ setUniform(cameraUniform, cameraPos);
+ setUniform(fogColorUniform, fogColor);
+ // setUniform(skyLightUniform, skyLight);
+ setUniform(lightMapUniform, lightmapBindPoint);
+ }
+
+ public void fillUniformDataForFog(LodFogConfig fogSettings) {
+ super.bind();
+ if (fogSettings.fogDrawMode != FogDrawMode.FOG_DISABLED) {
+ setUniform(fogEnabledUniform, true);
+ setUniform(nearFogEnabledUniform, fogSettings.fogDistance != FogDistance.FAR);
+ setUniform(farFogEnabledUniform, fogSettings.fogDistance != FogDistance.NEAR);
+ // near
+ setUniform(nearFogStartUniform, fogSettings.nearFogStart);
+ setUniform(nearFogEndUniform, fogSettings.nearFogEnd);
+ // far
+ setUniform(farFogStartUniform, fogSettings.farFogStart);
+ setUniform(farFogEndUniform, fogSettings.farFogEnd);
+ } else {
+ setUniform(fogEnabledUniform, false);
+ }
+ }
+
+}
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
new file mode 100644
index 000000000..367034067
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/render/objects/LightmapTexture.java
@@ -0,0 +1,54 @@
+package com.seibel.lod.core.render.objects;
+
+import org.lwjgl.opengl.GL20;
+import org.lwjgl.opengl.GL30;
+
+public class LightmapTexture {
+ public final int id;
+
+ public LightmapTexture() {
+ id = GL30.glGenTextures();
+ bind();
+ GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S, GL20.GL_CLAMP_TO_BORDER);
+ GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T, GL20.GL_CLAMP_TO_BORDER);
+ GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_NEAREST);
+ GL20.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_NEAREST);
+ }
+
+ public void bind() {
+ GL20.glBindTexture(GL20.GL_TEXTURE_2D, id);
+ }
+ public void unbind() {
+ GL20.glBindTexture(GL20.GL_TEXTURE_2D, 0);
+ }
+
+ public void free() {
+ GL20.glDeleteTextures(id);
+ }
+
+ public void fillData(int lightMapWidth, int lightMapHeight, int[] pixels) {
+ if (pixels.length != lightMapWidth*lightMapHeight)
+ throw new RuntimeException("Lightmap Width*Height not equal to pixels provided!");
+
+ // comment me out to see when the lightmap is changing
+// boolean same = true;
+// int badIndex = 0;
+// if (testArray != null && pixels != null)
+// for (int i = 0; i < pixels.length; i++)
+// {
+// if(pixels[i] != testArray[i])
+// {
+// same = false;
+// badIndex = i;
+// break;
+// }
+// }
+// testArray = pixels;
+// MC.sendChatMessage(same + " " + badIndex);
+
+ // comment this line out to prevent uploading the new lightmap
+ GL20.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, lightMapWidth,
+ lightMapHeight, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixels);
+ }
+
+}
diff --git a/src/main/java/com/seibel/lod/core/render/shader/LodShader.java b/src/main/java/com/seibel/lod/core/render/objects/Shader.java
similarity index 63%
rename from src/main/java/com/seibel/lod/core/render/shader/LodShader.java
rename to src/main/java/com/seibel/lod/core/render/objects/Shader.java
index 91a1ca397..f071c107e 100644
--- a/src/main/java/com/seibel/lod/core/render/shader/LodShader.java
+++ b/src/main/java/com/seibel/lod/core/render/objects/Shader.java
@@ -2,7 +2,7 @@
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
* licensed under the GNU GPL v3 License.
*
- * Copyright (C) 2020 James Seibel
+ * Copyright (C) 2021 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-package com.seibel.lod.core.render.shader;
+package com.seibel.lod.core.render.objects;
import java.io.BufferedReader;
import java.io.FileInputStream;
@@ -28,6 +28,8 @@ import java.io.InputStreamReader;
import org.lwjgl.opengl.GL20;
+import com.seibel.lod.core.api.ClientApi;
+
/**
* This object holds a OpenGL reference to a shader
* and allows for reading in and compiling a shader file.
@@ -35,31 +37,42 @@ import org.lwjgl.opengl.GL20;
* @author James Seibel
* @version 11-8-2021
*/
-public class LodShader
+public class Shader
{
/** OpenGL shader ID */
public final int id;
-
-
- /** Creates a shader with specified type. */
- public LodShader(int type)
- {
- id = GL20.glCreateShader(type);
- }
-
-
-
- /**
- * Loads a shader from file.
- *
+ /** Creates a shader with specified type.
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
* @param path File path of the shader
* @param absoluteFilePath If false the file path is relative to the resource jar folder.
- * @throws Exception if the shader fails to compile
+ * @throws RuntimeException if the shader fails to compile
*/
- public static LodShader loadShader(int type, String path, boolean absoluteFilePath)
+ public Shader(int type, String path, boolean absoluteFilePath)
{
+ ClientApi.LOGGER.info("Loading shader at "+path);
+ // Create an empty shader object
+ id = GL20.glCreateShader(type);
+ StringBuilder source = loadFile(path, absoluteFilePath);
+ GL20.glShaderSource(id, source);
+
+ GL20.glCompileShader(id);
+ // check if the shader compiled
+ int status = GL20.glGetShaderi(id, GL20.GL_COMPILE_STATUS);
+ if (status != GL20.GL_TRUE) {
+ String message = "Shader compiler error. Details: "+GL20.glGetShaderInfoLog(id);
+ free(); // important!
+ throw new RuntimeException(message);
+ }
+ ClientApi.LOGGER.info("Shader at "+path+" loaded sucessfully.");
+ }
+
+ // REMEMBER to always free the resource!
+ public void free() {
+ GL20.glDeleteShader(id);
+ }
+
+ private StringBuilder loadFile(String path, boolean absoluteFilePath) {
StringBuilder stringBuilder = new StringBuilder();
try
@@ -70,7 +83,7 @@ public class LodShader
// Throws FileNotFoundException
in = new FileInputStream(path); // Note: this should use OS path seperator
} else {
- in = LodShader.class.getClassLoader().getResourceAsStream(path); // Note: path seperator should be '/'
+ in = Shader.class.getClassLoader().getResourceAsStream(path); // Note: path seperator should be '/'
if (in == null) {
throw new FileNotFoundException("Shader file not found in resource: "+path);
}
@@ -86,39 +99,6 @@ public class LodShader
{
throw new RuntimeException("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
}
- CharSequence shaderFileSource = stringBuilder.toString();
-
- return createShader(type, shaderFileSource);
+ return stringBuilder;
}
-
- /**
- * Creates a shader with the specified type and source.
- *
- * @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
- * @param source Source of the shader
- * @throws Exception if the shader fails to compile
- */
- public static LodShader createShader(int type, CharSequence source)
- {
- LodShader shader = new LodShader(type);
- GL20.glShaderSource(shader.id, source);
- shader.compile();
-
- return shader;
- }
-
- /**
- * Compiles the shader and checks its status afterwards.
- * @throws Exception if the shader fails to compile
- */
- public void compile()
- {
- GL20.glCompileShader(id);
-
- // check if the shader compiled
- int status = GL20.glGetShaderi(id, GL20.GL_COMPILE_STATUS);
- if (status != GL20.GL_TRUE)
- throw new RuntimeException("Shader compiler error. Details: "+GL20.glGetShaderInfoLog(id));
- }
-
}
diff --git a/src/main/java/com/seibel/lod/core/render/shader/LodShaderProgram.java b/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java
similarity index 61%
rename from src/main/java/com/seibel/lod/core/render/shader/LodShaderProgram.java
rename to src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java
index e8c59b8dd..5d82438da 100644
--- a/src/main/java/com/seibel/lod/core/render/shader/LodShaderProgram.java
+++ b/src/main/java/com/seibel/lod/core/render/objects/ShaderProgram.java
@@ -17,12 +17,13 @@
* along with this program. If not, see .
*/
-package com.seibel.lod.core.render.shader;
+package com.seibel.lod.core.render.objects;
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;
@@ -39,126 +40,84 @@ import com.seibel.lod.core.objects.math.Vec3f;
* @author James Seibel
* @version 11-26-2021
*/
-public class LodShaderProgram
+public class ShaderProgram
{
/** Stores the handle of the program. */
public final int id;
/** Creates a shader program. */
- public LodShaderProgram()
+ // FIXME: A better way to set the fragData output name
+ public ShaderProgram(String vert, String frag, String fragDataOutputName)
{
+ Shader vertShader = new Shader(GL20.GL_VERTEX_SHADER, vert, false);
+ Shader fragShader = new Shader(GL20.GL_FRAGMENT_SHADER, frag, false);
+
id = GL20.glCreateProgram();
+
+ GL20.glAttachShader(this.id, vertShader.id);
+ GL20.glAttachShader(this.id, fragShader.id);
+ //GL30.glBindFragDataLocation(id, 0, fragDataOutputName);
+ GL20.glLinkProgram(this.id);
+
+ vertShader.free(); // important!
+ fragShader.free(); // important!
+
+ int status = GL20.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
+ if (status != GL20.GL_TRUE) {
+ String message = "Shader Link Error. Details: "+GL20.glGetProgramInfoLog(this.id);
+ free(); // important!
+ throw new RuntimeException(message);
+ }
}
-
-
/** Calls GL20.glUseProgram(this.id) */
- public void use()
+ public void bind()
{
GL20.glUseProgram(id);
}
-
- /**
- * Calls GL20.glAttachShader(this.id, shader.id)
- *
- * @param shader Shader to get attached
- */
- public void attachShader(LodShader shader)
- {
- GL20.glAttachShader(this.id, shader.id);
+ public void unbind() {
+ GL20.glUseProgram(0);
}
-
- /**
- * Links the shader program to the current OpenGL context.
- * @throws Exception Exception if the program failed to link
- */
- public void link()
+ // REMEMBER to always free the resource!
+ public void free()
{
- GL20.glLinkProgram(this.id);
- checkLinkStatus();
+ GL20.glDeleteProgram(id);
}
- /**
- * Checks if the program was linked successfully.
- * @throws Exception if the program failed to link
- */
- public void checkLinkStatus()
- {
- int status = GL20.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
- if (status != GL20.GL_TRUE)
- throw new RuntimeException("Shader Link Error. Details: "+GL20.glGetProgramInfoLog(this.id));
- }
-
-
-
-
- /**
+ /** WARNING: Slow native call! Cache it if possible!
* Gets the location of an attribute variable with specified name.
* Calls GL20.glGetAttribLocation(id, name)
*
* @param name Attribute name
- *
+ * @throws RuntimeException if attribute not found
* @return Location of the attribute
*/
public int getAttributeLocation(CharSequence name)
{
- return GL20.glGetAttribLocation(id, name);
+ int i = GL20.glGetAttribLocation(id, name);
+ if (i==-1) throw new RuntimeException("Attribute name not found: "+name);
+ return i;
}
- /**
- * Calls GL20.glEnableVertexAttribArray(location)
- *
- * @param location Location of the vertex attribute
- */
- public void enableVertexAttribute(int location)
- {
- GL20.glEnableVertexAttribArray(location);
- }
-
- /**
- * Calls GL20.glDisableVertexAttribArray(location)
- *
- * @param location Location of the vertex attribute
- */
- public void disableVertexAttribute(int location)
- {
- GL20.glDisableVertexAttribArray(location);
- }
-
- /**
- * Sets the vertex attribute pointer.
- * Calls GL20.glVertexAttribPointer(...)
- *
- * @param location Location of the vertex attribute
- * @param size Number of values per vertex
- * @param stride Offset between consecutive generic vertex attributes in
- * bytes
- * @param offset Offset of the first component of the first generic vertex
- * attribute in bytes
- */
- public void pointVertexAttribute(int location, int size, int stride, int offset)
- {
- GL20.glVertexAttribPointer(location, size, GL20.GL_FLOAT, false, stride, offset);
- }
-
- /**
+ /** WARNING: Slow native call! Cache it if possible!
* Gets the location of a uniform variable with specified name.
* Calls GL20.glGetUniformLocation(id, name)
*
* @param name Uniform name
- *
- * @return -1 = error value, 0 = first value, 1 = second value, etc.
+ * @throws RuntimeException if uniform not found
+ * @return Location of the Uniform
*/
public int getUniformLocation(CharSequence name)
{
- return GL20.glGetUniformLocation(id, name);
+ int i = GL20.glGetUniformLocation(id, name);
+ if (i==-1) throw new RuntimeException("Uniform name not found: "+name);
+ return i;
}
-
-
public void setUniform(int location, boolean value)
{
+ // This use -1 for false as that equals all one set
GL20.glUniform1i(location, value ? 1 : 0);
}
@@ -198,6 +157,4 @@ public class LodShaderProgram
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
new file mode 100644
index 000000000..cdd6d6a23
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/render/objects/VertexAttribute.java
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the Distant Horizon mod (formerly the LOD Mod),
+ * licensed under the GNU GPL v3 License.
+ *
+ * Copyright (C) 2021 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.lod.core.render.objects;
+
+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 {
+ public final int elementCount;
+ public final int glType;
+ public final boolean normalized;
+ public final int byteSize;
+ public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize) {
+ this.elementCount = elementCount;
+ this.glType = glType;
+ this.normalized = normalized;
+ this.byteSize = byteSize;
+ }
+ public static VertexPointer addFloatPointer(boolean normalized) {
+ return new VertexPointer(1, GL20.GL_FLOAT, normalized, 4);
+ }
+ public static VertexPointer addVec2Pointer(boolean normalized) {
+ return new VertexPointer(2, GL20.GL_FLOAT, normalized, 8);
+ }
+ public static VertexPointer addVec3Pointer(boolean normalized) {
+ return new VertexPointer(3, GL20.GL_FLOAT, normalized, 12);
+ }
+ public static VertexPointer addVec4Pointer(boolean normalized) {
+ return new VertexPointer(1, GL20.GL_FLOAT, normalized, 16);
+ }
+ public static VertexPointer addUnsignedBytePointer(boolean normalized) {
+ return new VertexPointer(1, GL20.GL_UNSIGNED_BYTE, normalized, 1);
+ }
+ public static VertexPointer addUnsignedBytesPointer(int elementCount, boolean normalized) {
+ return new VertexPointer(elementCount, GL20.GL_UNSIGNED_BYTE, normalized, elementCount);
+ }
+ public static VertexPointer addIntPointer(boolean normalized) {
+ return new VertexPointer(1, GL20.GL_INT, normalized, 4);
+ }
+ public static VertexPointer addIvec2Pointer(boolean normalized) {
+ return new VertexPointer(2, GL20.GL_INT, normalized, 8);
+ }
+ public static VertexPointer addIvec3Pointer(boolean normalized) {
+ return new VertexPointer(3, GL20.GL_INT, normalized, 12);
+ }
+ public static VertexPointer addIvec4Pointer(boolean normalized) {
+ return new VertexPointer(4, GL20.GL_INT, normalized, 16);
+ }
+ }
+
+
+ /** Stores the handle of the VertexAttribute. */
+ public final int id;
+
+ protected VertexAttribute() {
+ id = GL30.glGenVertexArrays();
+ }
+
+ public void bind() {
+ GL30.glBindVertexArray(id);
+ }
+ public void unbind() {
+ GL30.glBindVertexArray(0);
+ }
+
+ // REMEMBER to always free the resource!
+ public void free() {
+ GL30.glDeleteVertexArrays(id);
+ }
+
+ // Requires Vao binded
+ public abstract void bindBufferToAllBindingPoint(int buffer);
+ // Requires Vao 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
+ public abstract void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute);
+ // Requires Vao 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
new file mode 100644
index 000000000..9ee2b7c49
--- /dev/null
+++ b/src/main/java/com/seibel/lod/core/render/objects/VertexAttributePostGL43.java
@@ -0,0 +1,69 @@
+package com.seibel.lod.core.render.objects;
+
+import java.util.ArrayList;
+
+import org.lwjgl.opengl.GL43;
+
+import com.seibel.lod.core.api.ClientApi;
+import com.seibel.lod.core.render.objects.VertexAttribute.VertexPointer;
+
+// In OpenGL 4.3 and later, Vertex Attribute got a make-over.
+// Now it provides support for buffer binding points natively.
+// This means that setting up the VAO just use ONE native call when
+// binding to a buffer.
+//
+// Since I no longer needs to implement binding points, I also no
+// longer needs to keep track of Pointers.
+
+public final class VertexAttributePostGL43 extends VertexAttribute {
+
+ int numberOfBindingPoints = 0;
+ int strideSize = 0;
+
+ ArrayList pointersBuilder;
+
+ public VertexAttributePostGL43() {
+ super();
+ }
+
+ @Override
+ public void bindBufferToAllBindingPoint(int buffer) {
+ for (int i=0; i> bindingPointsToIndexBuilder;
+ ArrayList pointersBuilder;
+
+ public VertexAttributePreGL43() {
+ super();
+ bindingPointsToIndexBuilder = new TreeMap>();
+ pointersBuilder = new ArrayList();
+ }
+
+ @Override
+ public void bindBufferToAllBindingPoint(int buffer) {
+ GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, buffer);
+
+ for (int i=0; i intArray = bindingPointsToIndexBuilder.get(bindingPoint);
+ if (intArray == null) {
+ intArray = new TreeSet();
+ bindingPointsToIndexBuilder.put(bindingPoint, intArray);
+ }
+ intArray.add(attributeIndex);
+
+ while (pointersBuilder.size() <= attributeIndex) {
+ // This is dumb, but ArrayList doesn't have a resize, And this code
+ // should only be ran when it's building the Vertex Attribute anyways.
+ pointersBuilder.add(null);
+ }
+ pointersBuilder.set(attributeIndex, attribute);
+ }
+
+ @Override
+ public void completeAndCheck(int expectedStrideSize) {
+ int maxBindPointNumber = bindingPointsToIndexBuilder.lastKey();
+ bindingPointsToIndex = new int[maxBindPointNumber+1][];
+
+ bindingPointsToIndexBuilder.forEach((Integer i, TreeSet set) -> {
+ bindingPointsToIndex[i] = new int[set.size()];
+ Iterator iter = set.iterator();
+ for (int j = 0; j