diff --git a/api/src/main/java/com/seibel/distanthorizons/coreapi/util/jar/DeleteOnUnlock.java b/api/src/main/java/com/seibel/distanthorizons/coreapi/util/jar/DeleteOnUnlock.java
index d3ecc5967..f480dcf77 100644
--- a/api/src/main/java/com/seibel/distanthorizons/coreapi/util/jar/DeleteOnUnlock.java
+++ b/api/src/main/java/com/seibel/distanthorizons/coreapi/util/jar/DeleteOnUnlock.java
@@ -1,51 +1,179 @@
package com.seibel.distanthorizons.coreapi.util.jar;
import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.net.URLDecoder;
import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
- * Deletes the first file in the arguments when a lock is lifted from it (for Windows)
- * DON'T MOVE: If this class is moved, then the updater will no longer work on Windows
+ * Attempts to delete a given file path repeatedly until the file is unlocked.
+ * NOTE: don't move this class. If this class is moved, then old jars won't be able to find it.
*
* @author coolgi
*/
public class DeleteOnUnlock
{
+ public static int SUCCESS_EXIT_CODE = 0;
+ public static int FAIL_EXIT_CODE = 1;
+ public static int ERROR_EXIT_CODE = 2;
+
/** How long to wait after attempting once (milliseconds) */
- private static final int attemptSpeed = 100;
- /** How many minutes of attempting before it stops */
- private static final int timeout = 60; // Will continue attempting for an hour, if it doesnt unlock by then, then the computer must be way to slow
+ private static final int ATTEMPT_SPEED_IN_MS = 100;
+ /**
+ * How many minutes of attempting before it stops
+ * If the file isn't unlocked by then, the computer must be extremely slow or there is a bigger issue.
+ */
+ private static final int TIMEOUT_IN_MINUTES = 60;
+
+ /** can be null */
+ private static FileWriter logFileWriter;
+
/**
- * @param args Takes whatever the first argument is, treats it as a file, and deletes it once a process lock is lifted from it
- * Note: This argument should also be encoded in UTF-8
+ * args[0] the file path to delete. Should be encoded in UTF-8.
+ * args[1] the file path to write logs to, can be null.
*/
public static void main(String[] args)
{
+ String filePathToDelete = args[0];
+
+ // can be null, should only be used when debugging
+ String logFilePath = null;
+ if (args.length >= 2)
+ {
+ logFilePath = args[1]; // example: "C:/Users/James/Desktop/delete.log"
+ }
+
+
try
{
- File file = new File(
- URLDecoder.decode(args[0], "UTF-8")
- );
+ //===============//
+ // logging setup //
+ //===============//
+ // General logging note:
+ // system.err/out will only show up when debugging this program,
+ // when running DH as a whole it won't be shown.
+ // This is why file logging is necessary
- for (int i = 0; i < (60 / ((float) attemptSpeed/1000) ) * timeout; i++)
+ // does nothing if no log path was given
+ if (logFilePath != null && logFilePath.trim().length() != 0)
{
- if (file.renameTo(file)) // If it is able to be renamed, then it is unlocked and can be deleted
+ // create the file writer
+ File logFile = new File(logFilePath);
+ logFileWriter = new FileWriter(logFile, true);
+
+ // create the log file if necessary
+ try
{
- Files.delete(file.toPath());
- break;
+ if (!logFile.createNewFile() && !logFile.exists())
+ {
+ System.err.println("Unable to create log file at: [" + logFile.getPath() + "]");
+ }
+ }
+ catch (IOException e)
+ {
+ System.err.println(e.getMessage());
}
- TimeUnit.MILLISECONDS.sleep(attemptSpeed);
}
+
+
+
+ //====================//
+ // file deletion loop //
+ //====================//
+
+ File fileToDelete = new File(URLDecoder.decode(filePathToDelete, "UTF-8"));
+ log("starting deletion loop... Attempting to delete: ["+fileToDelete.getPath()+"].");
+
+ for (int i = 0; i < (60 / ((float) ATTEMPT_SPEED_IN_MS /1000) ) * TIMEOUT_IN_MINUTES; i++)
+ {
+ log("delete attempt ["+i+"]");
+
+ // If the file can be renamed then it is unlocked and can be deleted
+ if (fileToDelete.exists() && fileToDelete.renameTo(fileToDelete))
+ {
+ try
+ {
+ Files.delete(fileToDelete.toPath());
+
+ if (!fileToDelete.exists())
+ {
+ log("success");
+ break;
+ }
+ else
+ {
+ // shouldn't normally happen, but just in case
+ log("failed to delete without error");
+ }
+ }
+ catch (NoSuchFileException e)
+ {
+ // accidental success, the file is no longer there
+ log("no file found");
+ break;
+ }
+ catch (Exception e)
+ {
+ log("failed to delete with error: "+e.getMessage());
+ }
+ }
+
+ TimeUnit.MILLISECONDS.sleep(ATTEMPT_SPEED_IN_MS);
+ }
+
+
+ //==================//
+ // cleanup and exit //
+ //==================//
+
+ boolean programSuccess = !fileToDelete.exists();
+ log("delete program completed " + (programSuccess ? "successfully" : "unsuccessfully"));
+ System.exit(programSuccess ? SUCCESS_EXIT_CODE : FAIL_EXIT_CODE);
}
catch (Exception e)
{
+ String stackTrace = "";
+ for (StackTraceElement stackTraceElement : e.getStackTrace())
+ {
+ stackTrace += stackTraceElement.toString() + "\n";
+ }
+ log("Unexpected exception occurred: " + e.getMessage() + "\n\n" + stackTrace);
+
+
e.printStackTrace();
- throw new RuntimeException("Deletion failed");
+ System.exit(ERROR_EXIT_CODE);
}
}
+
+
+ /** writes the given message to the log file if a log file is present. */
+ private static void log(String message)
+ {
+ if (logFileWriter != null)
+ {
+ try
+ {
+ String localDateTime = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE) + " " + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);
+ logFileWriter.write(localDateTime + " - " + message + "\n");
+
+ // necessary to make sure the log file is written to
+ logFileWriter.flush();
+ }
+ catch (IOException e)
+ {
+ // Note: this will only show up when debugging this program, when running DH as a whole it won't be shown
+ System.err.println("Error writing to log: "+e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ }
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java
index df8f8d280..c43ed456f 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGraphicsConfig.java
@@ -54,7 +54,7 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
@Override
public IDhApiConfigValue chunkRenderDistance()
- { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance); }
+ { return new DhApiConfigValue(Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius); }
@Override
public IDhApiConfigValue renderingEnabled()
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
index a3edea52d..28693a882 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
@@ -31,7 +31,6 @@ import com.seibel.distanthorizons.core.config.types.enums.*;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
-import com.seibel.distanthorizons.core.util.EnumUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.coreapi.util.StringUtil;
@@ -71,7 +70,7 @@ public class Config
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
.build();
- public static ConfigLinkedEntry quickLodChunkRenderDistance = new ConfigLinkedEntry(Advanced.Graphics.Quality.lodChunkRenderDistance);
+ public static ConfigLinkedEntry quickLodChunkRenderDistance = new ConfigLinkedEntry(Advanced.Graphics.Quality.lodChunkRenderDistanceRadius);
public static ConfigEntry qualityPresetSetting = new ConfigEntry.Builder()
.set(EQualityPreset.MEDIUM) // the default value is set via the listener when accessed
@@ -155,7 +154,7 @@ public class Config
.setPerformance(EConfigEntryPerformance.MEDIUM)
.build();
- public static ConfigEntry lodChunkRenderDistance = new ConfigEntry.Builder()
+ public static ConfigEntry lodChunkRenderDistanceRadius = new ConfigEntry.Builder()
.setMinDefaultMax(32, 128, 4096)
.comment("The radius of the mod's render distance. (measured in chunks)")
.setPerformance(EConfigEntryPerformance.HIGH)
@@ -998,8 +997,7 @@ public class Config
public static ConfigEntry enableAutoUpdater = new ConfigEntry.Builder()
.set(
!SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class).getInstallationDirectory().getName().equals("run") // Guesses that a dev would use the directory called "run" as their running directory, and clients wont
- && !EPlatform.get().equals(EPlatform.WINDOWS) // FIXME: Updater on Windows is broken atm (and I have no idea on how to fix it)
- ) // disable the update notification in dev clients
+ ) // disable the updater in dev clients
.comment(""
+ "Automatically check for updates on game launch?")
.build();
@@ -1228,30 +1226,32 @@ public class Config
+ "")
.build();
- //public static ConfigEntry glContextMajorVersion = new ConfigEntry.Builder()
- // .setMinDefaultMax(3, 3, 4)
- // .comment("" +
- // "Can be changed if you experience crashing when loading into a world.\n" +
- // "Note: setting to an invalid version may also cause the game to crash.\n" +
- // "\n" +
- // "Defines the requested OpenGL context major version Distant Horizons will create. \n" +
- // "Possible values (DH requires 3.2 or higher at minimum): \n" +
- // "4.6, 4.5, 4.4, 4.3, 4.2, 4.1, 4.0 \n" +
- // "3.3, 3.2 \n" +
- // "")
- // .build();
- //public static ConfigEntry glContextMinorVersion = new ConfigEntry.Builder()
- // .setMinDefaultMax(0, 2, 6)
- // .comment("" +
- // "Can be changed if you experience crashing when loading into a world.\n" +
- // "Note: setting to an invalid version may also cause the game to crash.\n" +
- // "\n" +
- // "Defines the requested OpenGL context major version Distant Horizons will create. \n" +
- // "Possible values (DH requires 3.2 or higher at minimum): \n" +
- // "4.6, 4.5, 4.4, 4.3, 4.2, 4.1, 4.0 \n" +
- // "3.3, 3.2 \n" +
- // "")
- // .build();
+ public static ConfigEntry glContextMajorVersion = new ConfigEntry.Builder()
+ .setMinDefaultMax(0, 0, 4)
+ .comment("" +
+ "Can be changed if you experience crashing when loading into a world.\n" +
+ "Note: setting to an invalid version may also cause the game to crash.\n" +
+ "\n" +
+ "Leaving this value at causes DH to try all supported GL versions. \n" +
+ "\n" +
+ "Defines the requested OpenGL context major version Distant Horizons will create. \n" +
+ "Possible values (DH requires 3.2 or higher at minimum): \n" +
+ "4.6, 4.5, 4.4, 4.3, 4.2, 4.1, 4.0 \n" +
+ "3.3, 3.2 \n" +
+ "")
+ .build();
+ public static ConfigEntry glContextMinorVersion = new ConfigEntry.Builder()
+ .setMinDefaultMax(0, 0, 6)
+ .comment("" +
+ "Can be changed if you experience crashing when loading into a world.\n" +
+ "Note: setting to an invalid version may also cause the game to crash.\n" +
+ "\n" +
+ "Defines the requested OpenGL context major version Distant Horizons will create. \n" +
+ "Possible values (DH requires 3.2 or higher at minimum): \n" +
+ "4.6, 4.5, 4.4, 4.3, 4.2, 4.1, 4.0 \n" +
+ "3.3, 3.2 \n" +
+ "")
+ .build();
public static ConfigEntry glProfileMode = new ConfigEntry.Builder()
.set(EGlProfileMode.CORE)
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/gui/OpenGLConfigScreen.java b/core/src/main/java/com/seibel/distanthorizons/core/config/gui/OpenGLConfigScreen.java
index 586438062..71dad5506 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/gui/OpenGLConfigScreen.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/gui/OpenGLConfigScreen.java
@@ -20,13 +20,12 @@
package com.seibel.distanthorizons.core.config.gui;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
-import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
-import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
-import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.AbstractVertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
@@ -40,19 +39,19 @@ public class OpenGLConfigScreen extends AbstractScreen
ShaderProgram basicShader;
GLVertexBuffer sameContextBuffer;
GLVertexBuffer sharedContextBuffer;
- VertexAttribute va;
+ AbstractVertexAttribute va;
@Override
public void init()
{
System.out.println("init");
- va = VertexAttribute.create();
+ va = AbstractVertexAttribute.create();
va.bind();
// Pos
- va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
+ va.setVertexAttribute(0, 0, VertexPointer.addVec2Pointer(false));
// Color
- va.setVertexAttribute(0, 1, VertexAttribute.VertexPointer.addVec4Pointer(false));
+ va.setVertexAttribute(0, 1, VertexPointer.addVec4Pointer(false));
va.completeAndCheck(Float.BYTES * 6);
basicShader = new ShaderProgram("shaders/test/vert.vert", "shaders/test/frag.frag",
"fragColor", new String[]{"vPosition", "color"});
@@ -109,12 +108,12 @@ public class OpenGLConfigScreen extends AbstractScreen
if (System.currentTimeMillis() % 2000 < 1000)
{
sameContextBuffer.bind();
- va.bindBufferToAllBindingPoint(sameContextBuffer.getId());
+ va.bindBufferToAllBindingPoints(sameContextBuffer.getId());
}
else
{
sameContextBuffer.bind();
- va.bindBufferToAllBindingPoint(sharedContextBuffer.getId());
+ va.bindBufferToAllBindingPoints(sharedContextBuffer.getId());
}
// Render the square
GL32.glDrawArrays(GL32.GL_TRIANGLE_FAN, 0, 4);
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/jar/updater/SelfUpdater.java b/core/src/main/java/com/seibel/distanthorizons/core/jar/updater/SelfUpdater.java
index 253cec008..e8126b5cb 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/jar/updater/SelfUpdater.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/jar/updater/SelfUpdater.java
@@ -21,7 +21,6 @@ package com.seibel.distanthorizons.core.jar.updater;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
-import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.jar.JarUtils;
import com.seibel.distanthorizons.core.jar.ModGitInfo;
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
@@ -34,11 +33,10 @@ import com.seibel.distanthorizons.coreapi.util.jar.DeleteOnUnlock;
import org.apache.logging.log4j.Logger;
import javax.swing.*;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.MessageDigest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -53,7 +51,7 @@ public class SelfUpdater
private static final Logger LOGGER = DhLoggerBuilder.getLogger(SelfUpdater.class.getSimpleName());
/** As we cannot delete(or replace) the jar while the mod is running, we just have this to delete it once the game closes */
- public static boolean deleteOldOnClose = false;
+ public static boolean deleteOldJarOnJvmShutdown = false;
private static String currentJarSha = "";
private static String mcVersion = SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion();
@@ -205,7 +203,7 @@ public class SelfUpdater
throw new Exception("Checksum failed");
}
- deleteOldOnClose = true;
+ deleteOldJarOnJvmShutdown = true;
LOGGER.info(ModInfo.READABLE_NAME + " successfully updated. It will apply on game's relaunch");
new Thread(() -> {
@@ -253,7 +251,7 @@ public class SelfUpdater
}
fos.close();
- deleteOldOnClose = true;
+ deleteOldJarOnJvmShutdown = true;
LOGGER.info(ModInfo.READABLE_NAME + " successfully updated. It will apply on game's relaunch");
new Thread(() -> {
@@ -291,46 +289,108 @@ public class SelfUpdater
*/
public static void onClose()
{
- if (deleteOldOnClose)
+ if (!deleteOldJarOnJvmShutdown)
{
- try
+ return;
+ }
+
+
+
+ Path newJarPath = newFileLocation.toPath();
+ Path finalJarPath = JarUtils.jarFile.getParentFile().toPath().resolve(newFileLocation.getName());
+
+ try
+ {
+ // if a jar with the same already exists in the final location, delete it first (otherwise file move issues will occur)
+ Files.deleteIfExists(finalJarPath);
+
+ // move the new jar...
+ Files.move(newJarPath, finalJarPath);
+ // ...and delete the temp folder
+ Files.delete(newFileLocation.getParentFile().toPath());
+ }
+ catch (Exception e)
+ {
+ LOGGER.warn("Failed to move updated fire from [" + newFileLocation.getAbsolutePath() + "] " +
+ "to [" + JarUtils.jarFile.getParentFile().getAbsolutePath() + "], " +
+ "please move it manually", e);
+ }
+
+
+ try
+ {
+ // Get the Java binary
+ String javaHome = System.getProperty("java.home");
+ String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
+
+ // Run the file deletion jar in a new OS process,
+ // this is done to allow for deleting the current jar if the OS has a lock on it
+ String execCommand = "\""+ javaBin +"\" -cp \""+
+ finalJarPath.toAbsolutePath()+"\" " // run the deletion code from the new jar
+ +DeleteOnUnlock.class.getCanonicalName()+" "+
+ URLEncoder.encode(JarUtils.jarFile.getAbsolutePath(), "UTF-8"); // Encode the file location to prevent issues with special characters and spaces
+ Process deleteProcess = Runtime.getRuntime().exec(execCommand);
+
+ // check if the pro
+ if (deleteProcess.isAlive())
{
- Files.move(newFileLocation.toPath(), JarUtils.jarFile.getParentFile().toPath().resolve(newFileLocation.getName()));
- Files.delete(newFileLocation.getParentFile().toPath());
+ LOGGER.info(DeleteOnUnlock.class.getSimpleName()+" process started...");
}
- catch (Exception e)
+ else
{
- LOGGER.warn("Failed to move updated fire from [" + newFileLocation.getAbsolutePath() + "] to [" + JarUtils.jarFile.getParentFile().getAbsolutePath() + "], please move it manually");
- e.printStackTrace();
+ LOGGER.error(DeleteOnUnlock.class.getSimpleName()+" process failed to start.");
}
- try
+
+ // wait a moment so we can catch if there are any immediate issues with the process
+ Thread.sleep(250);
+
+ if (deleteProcess.isAlive())
{
- if (EPlatform.get() != EPlatform.WINDOWS)
+ LOGGER.info(DeleteOnUnlock.class.getSimpleName()+" running, old jar file at ["+JarUtils.jarFile.getAbsolutePath()+"] should be deleted after Minecraft's JVM shutdown has completed.");
+ }
+ else
+ {
+ int processExitCode = deleteProcess.exitValue();
+ if (processExitCode != DeleteOnUnlock.SUCCESS_EXIT_CODE)
{
- Files.delete(JarUtils.jarFile.toPath());
+ String failReason = (processExitCode == DeleteOnUnlock.FAIL_EXIT_CODE) ? "Timed out and was unable to delete the file." : "Ran into an unexpected error.";
+ LOGGER.error(DeleteOnUnlock.class.getSimpleName() + " " + failReason);
+ LOGGER.error(DeleteOnUnlock.class.getSimpleName() + " Logs are listed below:");
+
+ // record the process' logs
+ String normalOutput = convertInputStreamToString(deleteProcess.getInputStream());
+ LOGGER.info("process output: \n\n" + normalOutput);
+
+ // record the process' error logs
+ String errorOutput = convertInputStreamToString(deleteProcess.getInputStream());
+ LOGGER.error("process error output: \n\n" + errorOutput);
}
else
{
- // Gets the Java binary
- String javaHome = System.getProperty("java.home");
- String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
-
- // Execute the new jar, to delete the old jar once it detects the lock has been lifted
- Runtime.getRuntime().exec(
- "\""+ javaBin +"\" -cp \""+
- newFileLocation.getAbsolutePath()
- +"\" "+
- DeleteOnUnlock.class.getCanonicalName()
- +" "+
- URLEncoder.encode(JarUtils.jarFile.getAbsolutePath(), "UTF-8") // Encode the file location so that it doesnt have any spaces
- );
+ LOGGER.info(DeleteOnUnlock.class.getSimpleName() + " completed before JVM shutdown.");
}
}
- catch (Exception e)
- {
- LOGGER.warn("Failed to delete previous " + ModInfo.READABLE_NAME + " file, please delete it manually at [" + JarUtils.jarFile + "]");
- e.printStackTrace();
- }
+ }
+ catch (Exception e)
+ {
+ LOGGER.warn("Failed to delete previous " + ModInfo.READABLE_NAME + " file, please delete it manually at [" + JarUtils.jarFile + "]", e);
}
}
+
+ private static String convertInputStreamToString(InputStream inputStream)
+ {
+ try
+ {
+ byte[] bytes = new byte[inputStream.available()];
+ DataInputStream dataInputStream = new DataInputStream(inputStream);
+ dataInputStream.readFully(bytes);
+ return new String(bytes);
+ }
+ catch (IOException e)
+ {
+ return e.getMessage();
+ }
+ }
+
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java
index 45c90d51a..0bc03ace4 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java
@@ -79,15 +79,21 @@ public class ClientLevelModule implements Closeable
}
// TODO this should probably be handled via a config change listener
// recreate the RenderState if the render distance changes
- if (clientRenderState.quadtree.blockRenderDistanceRadius != Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
+ if (clientRenderState.quadtree.blockRenderDistanceDiameter != Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH * 2)
{
if (!this.ClientRenderStateRef.compareAndSet(clientRenderState, null))
{
return;
}
+ IClientLevelWrapper clientLevelWrapper = this.parentClientLevel.getClientLevelWrapper();
+ if (clientLevelWrapper == null)
+ {
+ return;
+ }
+
clientRenderState.close();
- clientRenderState = new ClientRenderState(parentClientLevel, parentClientLevel.getFileHandler(), parentClientLevel.getSaveStructure());
+ clientRenderState = new ClientRenderState(this.parentClientLevel, clientLevelWrapper, this.parentClientLevel.getFileHandler(), this.parentClientLevel.getSaveStructure());
if (!this.ClientRenderStateRef.compareAndSet(null, clientRenderState))
{
//FIXME: How to handle this?
@@ -117,9 +123,9 @@ public class ClientLevelModule implements Closeable
//========//
/** @return if the {@link ClientRenderState} was successfully swapped */
- public boolean startRenderer()
+ public boolean startRenderer(IClientLevelWrapper clientLevelWrapper)
{
- ClientRenderState ClientRenderState = new ClientRenderState(parentClientLevel, parentClientLevel.getFileHandler(), parentClientLevel.getSaveStructure());
+ ClientRenderState ClientRenderState = new ClientRenderState(parentClientLevel, clientLevelWrapper, parentClientLevel.getFileHandler(), parentClientLevel.getSaveStructure());
if (!this.ClientRenderStateRef.compareAndSet(null, ClientRenderState))
{
LOGGER.warn("Failed to start renderer due to concurrency");
@@ -280,13 +286,13 @@ public class ClientLevelModule implements Closeable
public final LodRenderer renderer;
public ClientRenderState(
- IDhClientLevel dhClientLevel, IFullDataSourceProvider fullDataSourceProvider,
+ IDhClientLevel dhClientLevel, IClientLevelWrapper clientLevelWrapper, IFullDataSourceProvider fullDataSourceProvider,
AbstractSaveStructure saveStructure)
{
- this.clientLevelWrapper = dhClientLevel.getClientLevelWrapper();
+ this.clientLevelWrapper = clientLevelWrapper;
this.renderSourceFileHandler = new RenderSourceFileHandler(fullDataSourceProvider, dhClientLevel, saveStructure);
- this.quadtree = new LodQuadTree(dhClientLevel, Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH,
+ this.quadtree = new LodQuadTree(dhClientLevel, Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH * 2,
// initial position is (0,0) just in case the player hasn't loaded in yet, the tree will be moved once the level starts ticking
0, 0,
this.renderSourceFileHandler);
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
index 824c8e636..316189645 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
@@ -64,7 +64,7 @@ public class DhClientLevel extends DhLevel implements IDhClientLevel
if (enableRendering)
{
- this.clientside.startRenderer();
+ this.clientside.startRenderer(clientLevelWrapper);
LOGGER.info("Started DHLevel for " + this.levelWrapper + " with saves at " + this.saveStructure);
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java
index cde8c6d0a..3f098d7f0 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java
@@ -120,10 +120,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS
// render //
//========//
- public void startRenderer(IClientLevelWrapper clientLevel)
- {
- clientside.startRenderer();
- }
+ public void startRenderer(IClientLevelWrapper clientLevel) { this.clientside.startRenderer(clientLevel); }
public void stopRenderer() { this.clientside.stopRenderer(); }
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java
index 6e4de26ed..04fc23659 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java
@@ -48,7 +48,7 @@ public class LodQuadTree extends QuadTree implements AutoClose
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
- public final int blockRenderDistanceRadius;
+ public final int blockRenderDistanceDiameter;
private final IRenderSourceProvider renderSourceProvider;
/**
@@ -77,15 +77,15 @@ public class LodQuadTree extends QuadTree implements AutoClose
//==============//
public LodQuadTree(
- IDhClientLevel level, int viewDistanceInBlocks,
+ IDhClientLevel level, int viewDiameterInBlocks,
int initialPlayerBlockX, int initialPlayerBlockZ,
IRenderSourceProvider provider)
{
- super(viewDistanceInBlocks, new DhBlockPos2D(initialPlayerBlockX, initialPlayerBlockZ), TREE_LOWEST_DETAIL_LEVEL);
+ super(viewDiameterInBlocks, new DhBlockPos2D(initialPlayerBlockX, initialPlayerBlockZ), TREE_LOWEST_DETAIL_LEVEL);
this.level = level;
this.renderSourceProvider = provider;
- this.blockRenderDistanceRadius = viewDistanceInBlocks;
+ this.blockRenderDistanceDiameter = viewDiameterInBlocks;
this.horizontalScaleChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.horizontalQuality, (newHorizontalScale) -> this.onHorizontalQualityChange());
}
@@ -364,7 +364,7 @@ public class LodQuadTree extends QuadTree implements AutoClose
}
else if (detail >= Byte.MAX_VALUE)
{
- return this.blockRenderDistanceRadius * 2;
+ return this.blockRenderDistanceDiameter * 2;
}
@@ -381,7 +381,7 @@ public class LodQuadTree extends QuadTree implements AutoClose
// The minimum detail level is done to prevent single corner sections rendering 1 detail level lower than the others.
// If not done corners may not be flush with the other LODs, which looks bad.
- byte minSectionDetailLevel = this.getDetailLevelFromDistance(this.blockRenderDistanceRadius); // get the minimum allowed detail level
+ byte minSectionDetailLevel = this.getDetailLevelFromDistance(this.blockRenderDistanceDiameter); // get the minimum allowed detail level
minSectionDetailLevel -= 1; // -1 so corners can't render lower than their adjacent neighbors. space
minSectionDetailLevel = (byte) Math.min(minSectionDetailLevel, this.treeMinDetailLevel); // don't allow rendering lower detail sections than what the tree contains
this.minRenderDetailLevel = (byte) Math.max(minSectionDetailLevel, this.maxRenderDetailLevel); // respect the user's selected max resolution if it is lower detail (IE they want 2x2 block, but minSectionDetailLevel is specifically for 1x1 block render resolution)
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
index 4d528dd84..4373120e8 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
@@ -171,7 +171,20 @@ public class GLProxy
long potentialLodBuilderGlContext = 0;
GLCapabilities potentialLodBuilderGlCapabilities = null;
- for (Pair supportedGlVersion : SUPPORTED_GL_VERSIONS)
+ int majorGlVersion = Config.Client.Advanced.Debugging.OpenGl.glContextMajorVersion.get();
+ int minorGlVersion = Config.Client.Advanced.Debugging.OpenGl.glContextMinorVersion.get();
+
+ ArrayList> glVersions = new ArrayList<>();
+ if (majorGlVersion != 0)
+ {
+ glVersions.add(new Pair<>(majorGlVersion, minorGlVersion));
+ }
+ else
+ {
+ glVersions.addAll(SUPPORTED_GL_VERSIONS);
+ }
+
+ for (Pair supportedGlVersion : glVersions)
{
int glMajorVersion = supportedGlVersion.first;
int glMinorVersion = supportedGlVersion.second;
@@ -193,8 +206,8 @@ public class GLProxy
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, glMajorVersion);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, glMinorVersion);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, debugContextEnabled ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
- GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, forwardCompatEnabled ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
+ GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, forwardCompatEnabled ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
int profileModeInt;
EGlProfileMode profileModeEnum = Config.Client.Advanced.Debugging.OpenGl.glProfileMode.get();
switch (profileModeEnum)
@@ -215,15 +228,15 @@ public class GLProxy
contextCreateErrorMessage =
"Failed to create OpenGL GLFW context for OpenGL Version: [" + glMajorVersion + "." + glMinorVersion + "] \n" +
"with Debugging: [" + (debugContextEnabled ? "Enabled" : "Disabled") + "], \n" +
- "Forward Compatibility: [" + (forwardCompatEnabled ? "Enabled" : "Disabled") + "], \n" +
+ "Forward Compatibility: [" + (true ? "Enabled" : "Disabled") + "], \n" +
"and Profile: [" + profileModeEnum.name() + "]. ";
// try creating the Lod Builder context
- potentialLodBuilderGlContext = GLFW.glfwCreateWindow(1, 1, "LOD Builder Window", 0L, this.minecraftGlContext);
+ potentialLodBuilderGlContext = GLFW.glfwCreateWindow(64, 64, "LOD Builder Window", 0L, this.minecraftGlContext);
if (potentialLodBuilderGlContext == 0)
{
- GL_LOGGER.debug(contextCreateErrorMessage);
+ GL_LOGGER.info(contextCreateErrorMessage);
GL_LOGGER.debug("Minecraft GL Capabilities:\n [\n" + ReflectionUtil.getAllFieldValuesAsString(this.minecraftGlCapabilities) + "\n]\n");
continue;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLState.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLState.java
index 216a2067f..0b25f703b 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLState.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLState.java
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.core.render.glObject;
import org.lwjgl.opengl.GL32;
+// TODO make this Closable or AutoClosable so it can be used with try-resource blocks
public class GLState
{
private static final int FBO_MAX = 4;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/LightmapTexture.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/LightmapTexture.java
index 674cb2e7b..f15b59b0a 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/LightmapTexture.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/LightmapTexture.java
@@ -73,7 +73,7 @@ public class LightmapTexture
MC.sendChatMessage(same + " " + badIndex);
*/
// comment this line out to prevent uploading the new lightmap
- GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA, lightMapWidth * lightMapHeight,
+ GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA8, lightMapWidth * lightMapHeight,
1, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_BYTE, pixels);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_WRAP_S, GL32.GL_CLAMP_TO_BORDER);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_WRAP_T, GL32.GL_CLAMP_TO_BORDER);
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/AbstractVertexAttribute.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/AbstractVertexAttribute.java
new file mode 100644
index 000000000..3c7267c71
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/AbstractVertexAttribute.java
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.core.render.glObject.vertexAttribute;
+
+import com.seibel.distanthorizons.core.render.glObject.GLProxy;
+import org.lwjgl.opengl.GL32;
+
+/**
+ * Base for binding/unbinding Vertex Attribute objects (VAO's).
+ *
+ * @see VertexAttributePostGL43
+ * @see VertexAttributePreGL43
+ */
+public abstract class AbstractVertexAttribute
+{
+ /** Stores the handle of the AbstractVertexAttribute. */
+ public final int id;
+
+
+
+ //==============//
+ // constructors //
+ //==============//
+
+ // This will bind AbstractVertexAttribute
+ protected AbstractVertexAttribute()
+ {
+ this.id = GL32.glGenVertexArrays();
+ GL32.glBindVertexArray(this.id);
+ }
+
+ public static AbstractVertexAttribute create()
+ {
+ if (GLProxy.getInstance().VertexAttributeBufferBindingSupported)
+ {
+ return new VertexAttributePostGL43();
+ }
+ else
+ {
+ return new VertexAttributePreGL43();
+ }
+ }
+
+
+
+ //=========//
+ // binding //
+ //=========//
+
+ public void bind() { GL32.glBindVertexArray(this.id); }
+ public void unbind() { GL32.glBindVertexArray(0); }
+
+ /** Always remember to always free your resources! */
+ public void free() { GL32.glDeleteVertexArrays(this.id); }
+
+
+
+ //==================//
+ // abstract methods //
+ //==================//
+
+ /** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
+ public abstract void bindBufferToAllBindingPoints(int buffer);
+ /** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
+ public abstract void bindBufferToBindingPoint(int buffer, int bindingPoint);
+ /** Requires both AbstractVertexAttribute to be bound */
+ public abstract void unbindBuffersFromAllBindingPoint();
+ /** Requires both AbstractVertexAttribute to be bound */
+ public abstract void unbindBuffersFromBindingPoint(int bindingPoint);
+ /** Requires both AbstractVertexAttribute to be bound */
+ public abstract void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute);
+ /** Requires both AbstractVertexAttribute to be bound */
+ public abstract void completeAndCheck(int expectedStrideSize);
+
+}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttribute.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttribute.java
deleted file mode 100644
index ff8bbdd65..000000000
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttribute.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * This file is part of the Distant Horizons mod
- * licensed under the GNU LGPL v3 License.
- *
- * Copyright (C) 2020-2023 James Seibel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package com.seibel.distanthorizons.core.render.glObject.vertexAttribute;
-
-import com.seibel.distanthorizons.core.render.glObject.GLProxy;
-import com.seibel.distanthorizons.coreapi.util.MathUtil;
-import org.lwjgl.opengl.GL32;
-
-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 final boolean useInteger;
- public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize, boolean useInteger)
- {
- this.elementCount = elementCount;
- this.glType = glType;
- this.normalized = normalized;
- this.byteSize = byteSize;
- this.useInteger = useInteger;
- }
- public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize)
- {
- this(elementCount, glType, normalized, byteSize, false);
- }
- private static int _align(int bytes)
- {
- return MathUtil.ceilDiv(bytes, 4) * 4;
- }
-
- public static VertexPointer addFloatPointer(boolean normalized)
- {
- return new VertexPointer(1, GL32.GL_FLOAT, normalized, 4);
- }
- public static VertexPointer addVec2Pointer(boolean normalized)
- {
- return new VertexPointer(2, GL32.GL_FLOAT, normalized, 8);
- }
- public static VertexPointer addVec3Pointer(boolean normalized)
- {
- return new VertexPointer(3, GL32.GL_FLOAT, normalized, 12);
- }
- public static VertexPointer addVec4Pointer(boolean normalized)
- {
- return new VertexPointer(4, GL32.GL_FLOAT, normalized, 16);
- }
- public static VertexPointer addUnsignedBytePointer(boolean normalized, boolean useInteger)
- {
- return new VertexPointer(1, GL32.GL_UNSIGNED_BYTE, normalized, 4, useInteger); // Always aligned to 4 bytes
- }
- public static VertexPointer addUnsignedBytesPointer(int elementCount, boolean normalized, boolean useInteger)
- {
- return new VertexPointer(elementCount, GL32.GL_UNSIGNED_BYTE, normalized, _align(elementCount), useInteger); // aligned to 4 bytes
- }
- public static VertexPointer addUnsignedShortsPointer(int elementCount, boolean normalized, boolean useInteger)
- {
- return new VertexPointer(elementCount, GL32.GL_UNSIGNED_SHORT, normalized, _align(elementCount * 2), useInteger);
- }
- public static VertexPointer addShortsPointer(int elementCount, boolean normalized, boolean useInteger)
- {
- return new VertexPointer(elementCount, GL32.GL_SHORT, normalized, _align(elementCount * 2), useInteger);
- }
- public static VertexPointer addIntPointer(boolean normalized, boolean useInteger)
- {
- return new VertexPointer(1, GL32.GL_INT, normalized, 4, useInteger);
- }
- public static VertexPointer addIvec2Pointer(boolean normalized, boolean useInteger)
- {
- return new VertexPointer(2, GL32.GL_INT, normalized, 8, useInteger);
- }
- public static VertexPointer addIvec3Pointer(boolean normalized, boolean useInteger)
- {
- return new VertexPointer(3, GL32.GL_INT, normalized, 12, useInteger);
- }
- public static VertexPointer addIvec4Pointer(boolean normalized, boolean useInteger)
- {
- return new VertexPointer(4, GL32.GL_INT, normalized, 16, useInteger);
- }
-
- }
-
-
- /** Stores the handle of the VertexAttribute. */
- public final int id;
-
- // This will bind VertexAttribute
- protected VertexAttribute()
- {
- id = GL32.glGenVertexArrays();
- GL32.glBindVertexArray(id);
- }
-
- public static VertexAttribute create()
- {
- if (GLProxy.getInstance().VertexAttributeBufferBindingSupported)
- {
- return new VertexAttributePostGL43();
- }
- else
- {
- return new VertexAttributePreGL43();
- }
- }
-
- // This will bind VertexAttribute
- public void bind()
- {
- GL32.glBindVertexArray(id);
- }
-
- // This will unbind VertexAttribute
- public void unbind()
- {
- GL32.glBindVertexArray(0);
- }
-
- // REMEMBER to always free the resource!
- public void free()
- {
- GL32.glDeleteVertexArrays(id);
- }
-
- // Requires VertexAttribute binded, VertexBuffer binded
- public abstract void bindBufferToAllBindingPoint(int buffer);
- // Requires VertexAttribute binded, VertexBuffer binded
- public abstract void bindBufferToBindingPoint(int buffer, int bindingPoint);
- // 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 VertexAttribute binded
- public abstract void completeAndCheck(int expectedStrideSize);
-
-}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePostGL43.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePostGL43.java
index de2b06bb8..6ab7e3ba8 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePostGL43.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePostGL43.java
@@ -22,87 +22,126 @@ package com.seibel.distanthorizons.core.render.glObject.vertexAttribute;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import org.lwjgl.opengl.GL43;
-// 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
+/**
+ * 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 is just use ONE native call when
+ * binding to a buffer.
+ *
+ * Since I no longer need to implement binding points, I also no
+ * longer needs to keep track of Pointers.
+ */
+public final class VertexAttributePostGL43 extends AbstractVertexAttribute
{
-
int numberOfBindingPoints = 0;
int strideSize = 0;
- // This will bind VertexAttribute
+
+
+ //=============//
+ // constructor //
+ //=============//
+
+ /** This will bind the {@link AbstractVertexAttribute} */
public VertexAttributePostGL43()
{
- super(); // also bind VertexAttribute
+ super(); // also bind AbstractVertexAttribute
}
+
+
+ //=========//
+ // binding //
+ //=========//
+
+ /** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
- // Requires VertexAttribute binded, VertexBuffer binded
- public void bindBufferToAllBindingPoint(int buffer)
+ public void bindBufferToAllBindingPoints(int buffer)
{
- for (int i = 0; i < numberOfBindingPoints; i++)
+ for (int i = 0; i < this.numberOfBindingPoints; i++)
{
- GL43.glBindVertexBuffer(i, buffer, 0, strideSize);
+ GL43.glBindVertexBuffer(i, buffer, 0, this.strideSize);
}
}
+ /** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
- // Requires VertexAttribute binded, VertexBuffer binded
public void bindBufferToBindingPoint(int buffer, int bindingPoint)
{
- GL43.glBindVertexBuffer(bindingPoint, buffer, 0, strideSize);
+ GL43.glBindVertexBuffer(bindingPoint, buffer, 0, this.strideSize);
}
+
+
+ //===========//
+ // unbinding //
+ //===========//
+
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void unbindBuffersFromAllBindingPoint()
{
- for (int i = 0; i < numberOfBindingPoints; i++)
+ for (int i = 0; i < this.numberOfBindingPoints; i++)
{
GL43.glBindVertexBuffer(i, 0, 0, 0);
}
}
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void unbindBuffersFromBindingPoint(int bindingPoint)
{
GL43.glBindVertexBuffer(bindingPoint, 0, 0, 0);
}
+
+
+ //==========================//
+ // manual attribute setting //
+ //==========================//
+
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute)
{
if (attribute.useInteger)
- GL43.glVertexAttribIFormat(attributeIndex, attribute.elementCount, attribute.glType, strideSize);
+ {
+ GL43.glVertexAttribIFormat(attributeIndex, attribute.elementCount, attribute.glType, this.strideSize);
+ }
else
+ {
GL43.glVertexAttribFormat(attributeIndex, attribute.elementCount, attribute.glType,
- attribute.normalized, strideSize); // Here strideSize is new attrib offset
- strideSize += attribute.byteSize;
- if (numberOfBindingPoints <= bindingPoint) numberOfBindingPoints = bindingPoint + 1;
+ attribute.normalized, this.strideSize); // Here strideSize is new attrib offset
+ }
+
+ this.strideSize += attribute.byteSize;
+ if (this.numberOfBindingPoints <= bindingPoint)
+ {
+ this.numberOfBindingPoints = bindingPoint + 1;
+ }
GL43.glVertexAttribBinding(attributeIndex, bindingPoint);
GL43.glEnableVertexAttribArray(attributeIndex);
}
+
+
+ //============//
+ // validation //
+ //============//
+
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void completeAndCheck(int expectedStrideSize)
{
- if (strideSize != expectedStrideSize)
+ if (this.strideSize != expectedStrideSize)
{
- GLProxy.GL_LOGGER.error("Vertex Attribute calculated stride size " + strideSize +
+ GLProxy.GL_LOGGER.error("Vertex Attribute calculated stride size " + this.strideSize +
" does not match the provided expected stride size " + expectedStrideSize + "!");
throw new IllegalArgumentException("Vertex Attribute Incorrect Format");
}
- GLProxy.GL_LOGGER.info("Vertex Attribute (GL43+) completed. It contains " + numberOfBindingPoints
- + " binding points and a stride size of " + strideSize);
+
+ GLProxy.GL_LOGGER.info("Vertex Attribute (GL43+) completed. It contains " + this.numberOfBindingPoints
+ + " binding points and a stride size of " + this.strideSize);
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePreGL43.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePreGL43.java
index 4e5c8a1f0..72cefef2f 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePreGL43.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexAttributePreGL43.java
@@ -28,11 +28,10 @@ import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import org.lwjgl.opengl.GL32;
-public final class VertexAttributePreGL43 extends VertexAttribute
+public final class VertexAttributePreGL43 extends AbstractVertexAttribute
{
-
- // I tried to use as much raw arrays as possible as those lookups
- // happens every frame, and the speed directly effects fps
+ // I tried to use raw arrays as much as possible since those lookups
+ // happen every frame, and the speed directly affects fps
int strideSize = 0;
int[][] bindingPointsToIndex;
VertexPointer[] pointers;
@@ -41,153 +40,204 @@ public final class VertexAttributePreGL43 extends VertexAttribute
TreeMap> bindingPointsToIndexBuilder;
ArrayList pointersBuilder;
- // This will bind VertexAttribute
+
+
+ //=============//
+ // constructor //
+ //=============//
+
+ /** This will bind the {@link AbstractVertexAttribute} */
public VertexAttributePreGL43()
{
- super(); // also bind VertexAttribute
- bindingPointsToIndexBuilder = new TreeMap>();
- pointersBuilder = new ArrayList();
+ super(); // also bind AbstractVertexAttribute
+ this.bindingPointsToIndexBuilder = new TreeMap<>();
+ this.pointersBuilder = new ArrayList<>();
}
+
+
+ //=========//
+ // binding //
+ //=========//
+
+ /** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
- // Requires VertexAttribute binded, VertexBuffer binded
- public void bindBufferToAllBindingPoint(int buffer)
+ public void bindBufferToAllBindingPoints(int buffer)
{
- for (int i = 0; i < pointers.length; i++)
+ for (int i = 0; i < this.pointers.length; i++)
{
GL32.glEnableVertexAttribArray(i);
}
- for (int i = 0; i < pointers.length; i++)
+ for (int i = 0; i < this.pointers.length; i++)
{
- VertexPointer pointer = pointers[i];
- if (pointer == null) continue;
+ VertexPointer pointer = this.pointers[i];
+ if (pointer == null)
+ {
+ continue;
+ }
+
if (pointer.useInteger)
+ {
GL32.glVertexAttribIPointer(i, pointer.elementCount, pointer.glType,
- strideSize, pointersOffset[i]);
- else GL32.glVertexAttribPointer(i, pointer.elementCount, pointer.glType,
- pointer.normalized, strideSize, pointersOffset[i]);
+ this.strideSize, this.pointersOffset[i]);
+ }
+ else
+ {
+ GL32.glVertexAttribPointer(i, pointer.elementCount, pointer.glType,
+ pointer.normalized, this.strideSize, this.pointersOffset[i]);
+ }
}
}
+ /** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
- // Requires VertexAttribute binded, VertexBuffer binded
public void bindBufferToBindingPoint(int buffer, int bindingPoint)
{
- int[] toBind = bindingPointsToIndex[bindingPoint];
+ int[] bindingPointIndexes = this.bindingPointsToIndex[bindingPoint];
- for (int k : toBind)
+ for (int bindingPointIndex : bindingPointIndexes)
{
- GL32.glEnableVertexAttribArray(k);
+ GL32.glEnableVertexAttribArray(bindingPointIndex);
}
- for (int j : toBind)
+ for (int bindingPointIndex : bindingPointIndexes)
{
- VertexPointer pointer = pointers[j];
+ VertexPointer pointer = this.pointers[bindingPointIndex];
if (pointer == null)
+ {
continue;
+ }
+
if (pointer.useInteger)
- GL32.glVertexAttribIPointer(j, pointer.elementCount, pointer.glType,
- strideSize, pointersOffset[j]);
- else GL32.glVertexAttribPointer(j, pointer.elementCount, pointer.glType,
- pointer.normalized, strideSize, pointersOffset[j]);
+ {
+ GL32.glVertexAttribIPointer(bindingPointIndex, pointer.elementCount, pointer.glType,
+ this.strideSize, this.pointersOffset[bindingPointIndex]);
+ }
+ else
+ {
+ GL32.glVertexAttribPointer(bindingPointIndex, pointer.elementCount, pointer.glType,
+ pointer.normalized, this.strideSize, this.pointersOffset[bindingPointIndex]);
+ }
}
}
+
+
+
+ //===========//
+ // unbinding //
+ //===========//
+
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void unbindBuffersFromAllBindingPoint()
{
- for (int i = 0; i < pointers.length; i++)
+ for (int i = 0; i < this.pointers.length; i++)
{
GL32.glDisableVertexAttribArray(i);
}
}
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void unbindBuffersFromBindingPoint(int bindingPoint)
{
- int[] toBind = bindingPointsToIndex[bindingPoint];
-
- for (int j : toBind)
+ int[] bindingPointIndexes = this.bindingPointsToIndex[bindingPoint];
+ for (int bindingPointIndex : bindingPointIndexes)
{
- GL32.glDisableVertexAttribArray(j);
+ GL32.glDisableVertexAttribArray(bindingPointIndex);
}
}
+
+
+ //==========================//
+ // manual attribute setting //
+ //==========================//
+
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void setVertexAttribute(int bindingPoint, int attributeIndex, VertexPointer attribute)
{
- TreeSet intArray = bindingPointsToIndexBuilder.computeIfAbsent(bindingPoint, k -> new TreeSet());
+ TreeSet intArray = this.bindingPointsToIndexBuilder.computeIfAbsent(bindingPoint, k -> new TreeSet<>());
intArray.add(attributeIndex);
- while (pointersBuilder.size() <= attributeIndex)
+ while (this.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);
+ // should only be run when it's building the Vertex Attribute anyway.
+ this.pointersBuilder.add(null);
}
- pointersBuilder.set(attributeIndex, attribute);
+ this.pointersBuilder.set(attributeIndex, attribute);
}
+
+
+ //============//
+ // validation //
+ //============//
+
+ /** Requires AbstractVertexAttribute to be bound */
@Override
- // Requires VertexAttribute binded
public void completeAndCheck(int expectedStrideSize)
{
- int maxBindPointNumber = bindingPointsToIndexBuilder.lastKey();
- bindingPointsToIndex = new int[maxBindPointNumber + 1][];
+ int maxBindPointNumber = this.bindingPointsToIndexBuilder.lastKey();
+ this.bindingPointsToIndex = new int[maxBindPointNumber + 1][];
- bindingPointsToIndexBuilder.forEach((Integer i, TreeSet set) -> {
- bindingPointsToIndex[i] = new int[set.size()];
+ this.bindingPointsToIndexBuilder.forEach((Integer i, TreeSet set) ->
+ {
+ this.bindingPointsToIndex[i] = new int[set.size()];
Iterator iter = set.iterator();
for (int j = 0; j < set.size(); j++)
{
- bindingPointsToIndex[i][j] = iter.next();
+ this.bindingPointsToIndex[i][j] = iter.next();
}
});
- pointers = pointersBuilder.toArray(new VertexPointer[pointersBuilder.size()]);
- pointersOffset = new int[pointers.length];
- pointersBuilder = null; // Release the builder
- bindingPointsToIndexBuilder = null; // Release the builder
+ this.pointers = this.pointersBuilder.toArray(new VertexPointer[this.pointersBuilder.size()]);
+ this.pointersOffset = new int[this.pointers.length];
+ this.pointersBuilder = null; // Release the builder
+ this.bindingPointsToIndexBuilder = null; // Release the builder
// Check if all pointers are valid
int currentOffset = 0;
- for (int i = 0; i < pointers.length; i++)
+ for (int i = 0; i < this.pointers.length; i++)
{
- VertexPointer pointer = pointers[i];
+ VertexPointer pointer = this.pointers[i];
if (pointer == null)
{
GLProxy.GL_LOGGER.warn("Vertex Attribute index " + i + " is not set! No index should be skipped normally!");
continue;
}
- pointersOffset[i] = currentOffset;
+ this.pointersOffset[i] = currentOffset;
currentOffset += pointer.byteSize;
}
+
if (currentOffset != expectedStrideSize)
{
GLProxy.GL_LOGGER.error("Vertex Attribute calculated stride size " + currentOffset +
" does not match the provided expected stride size " + expectedStrideSize + "!");
throw new IllegalArgumentException("Vertex Attribute Incorrect Format");
}
- strideSize = currentOffset;
+ this.strideSize = currentOffset;
GLProxy.GL_LOGGER.info("Vertex Attribute (pre GL43) completed.");
// Debug logging
GLProxy.GL_LOGGER.debug("AttributeIndex: ElementCount, glType, normalized, strideSize, offset");
- for (int i = 0; i < pointers.length; i++)
+ for (int i = 0; i < this.pointers.length; i++)
{
- VertexPointer pointer = pointers[i];
+ VertexPointer pointer = this.pointers[i];
if (pointer == null)
{
GLProxy.GL_LOGGER.debug(i + ": Null!!!!");
- continue;
}
- GLProxy.GL_LOGGER.debug(i + ": " + pointer.elementCount + ", " +
- pointer.glType + ", " + pointer.normalized + ", " + strideSize + ", " + pointersOffset[i]);
+ else
+ {
+ GLProxy.GL_LOGGER.debug(i + ": " + pointer.elementCount + ", " +
+ pointer.glType + ", " + pointer.normalized + ", " + this.strideSize + ", " + this.pointersOffset[i]);
+ }
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexPointer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexPointer.java
new file mode 100644
index 000000000..3ce08bef1
--- /dev/null
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/vertexAttribute/VertexPointer.java
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the Distant Horizons mod
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2023 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.core.render.glObject.vertexAttribute;
+
+import com.seibel.distanthorizons.coreapi.util.MathUtil;
+import org.lwjgl.opengl.GL32;
+
+public final class VertexPointer
+{
+ public final int elementCount;
+ public final int glType;
+ public final boolean normalized;
+ public final int byteSize;
+ public final boolean useInteger;
+
+
+
+ // basic constructors //
+
+ public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize, boolean useInteger)
+ {
+ this.elementCount = elementCount;
+ this.glType = glType;
+ this.normalized = normalized;
+ this.byteSize = byteSize;
+ this.useInteger = useInteger;
+ }
+ public VertexPointer(int elementCount, int glType, boolean normalized, int byteSize)
+ {
+ this(elementCount, glType, normalized, byteSize, false);
+ }
+ private static int _align(int bytes) { return MathUtil.ceilDiv(bytes, 4) * 4; }
+
+
+
+ // named constructors //
+
+ public static VertexPointer addFloatPointer(boolean normalized) { return new VertexPointer(1, GL32.GL_FLOAT, normalized, Float.BYTES); }
+ public static VertexPointer addVec2Pointer(boolean normalized) { return new VertexPointer(2, GL32.GL_FLOAT, normalized, Float.BYTES * 2); }
+ public static VertexPointer addVec3Pointer(boolean normalized) { return new VertexPointer(3, GL32.GL_FLOAT, normalized, Float.BYTES * 3); }
+ public static VertexPointer addVec4Pointer(boolean normalized) { return new VertexPointer(4, GL32.GL_FLOAT, normalized, Float.BYTES * 4); }
+ /** Always aligned to 4 bytes */
+ public static VertexPointer addUnsignedBytePointer(boolean normalized, boolean useInteger) { return new VertexPointer(1, GL32.GL_UNSIGNED_BYTE, normalized, 4, useInteger); }
+ /** aligned to 4 bytes */
+ public static VertexPointer addUnsignedBytesPointer(int elementCount, boolean normalized, boolean useInteger) { return new VertexPointer(elementCount, GL32.GL_UNSIGNED_BYTE, normalized, _align(elementCount), useInteger); }
+ public static VertexPointer addUnsignedShortsPointer(int elementCount, boolean normalized, boolean useInteger) { return new VertexPointer(elementCount, GL32.GL_UNSIGNED_SHORT, normalized, _align(elementCount * 2), useInteger); }
+ public static VertexPointer addShortsPointer(int elementCount, boolean normalized, boolean useInteger) { return new VertexPointer(elementCount, GL32.GL_SHORT, normalized, _align(elementCount * 2), useInteger); }
+ public static VertexPointer addIntPointer(boolean normalized, boolean useInteger) { return new VertexPointer(1, GL32.GL_INT, normalized, 4, useInteger); }
+ public static VertexPointer addIVec2Pointer(boolean normalized, boolean useInteger) { return new VertexPointer(2, GL32.GL_INT, normalized, 8, useInteger); }
+ public static VertexPointer addIVec3Pointer(boolean normalized, boolean useInteger) { return new VertexPointer(3, GL32.GL_INT, normalized, 12, useInteger); }
+ public static VertexPointer addIVec4Pointer(boolean normalized, boolean useInteger) { return new VertexPointer(4, GL32.GL_INT, normalized, 16, useInteger); }
+
+}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java
index 8b8396237..4d205270a 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java
@@ -33,7 +33,8 @@ import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLElementBuffer;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
-import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.AbstractVertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
@@ -66,7 +67,7 @@ public class DebugRenderer
private ShaderProgram basicShader;
private GLVertexBuffer boxBuffer;
private GLElementBuffer boxOutlineBuffer;
- private VertexAttribute va;
+ private AbstractVertexAttribute va;
private boolean init = false;
// used when rendering
@@ -155,10 +156,10 @@ public class DebugRenderer
}
this.init = true;
- this.va = VertexAttribute.create();
+ this.va = AbstractVertexAttribute.create();
this.va.bind();
// Pos
- this.va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec3Pointer(false));
+ this.va.setVertexAttribute(0, 0, VertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag",
"fragColor", new String[]{"vPosition"});
@@ -206,7 +207,7 @@ public class DebugRenderer
this.basicShader.bind();
this.va.bind();
- this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId());
+ this.va.bindBufferToAllBindingPoints(this.boxBuffer.getId());
this.boxOutlineBuffer.bind();
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderProgram.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderProgram.java
index 2f7a30ef1..bd2d64a73 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderProgram.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderProgram.java
@@ -24,9 +24,10 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.render.glObject.shader.Shader;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
-import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.AbstractVertexAttribute;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttributePostGL43;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttributePreGL43;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.render.fog.LodFogConfig;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
@@ -40,7 +41,7 @@ public class LodRenderProgram extends ShaderProgram
public static final String FRAGMENT_SHADER_PATH = "shaders/flat_shaded.frag";
private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class);
- public final VertexAttribute vao;
+ public final AbstractVertexAttribute vao;
// Uniforms
public final int combinedMatUniform;
@@ -66,7 +67,7 @@ public class LodRenderProgram extends ShaderProgram
private final LodFogConfig fogConfig;
- // This will bind VertexAttribute
+ // This will bind AbstractVertexAttribute
public LodRenderProgram(LodFogConfig fogConfig)
{
super(() -> Shader.loadFile(fogConfig.earthCurveRatio != 0 ? VERTEX_CURVE_SHADER_PATH : VERTEX_SHADER_PATH,
@@ -97,15 +98,13 @@ public class LodRenderProgram extends ShaderProgram
// TODO: Add better use of the LODFormat thing
int vertexByteCount = LodUtil.LOD_VERTEX_FORMAT.getByteSize();
if (GLProxy.getInstance().VertexAttributeBufferBindingSupported)
- vao = new VertexAttributePostGL43(); // also binds VertexAttribute
+ vao = new VertexAttributePostGL43(); // also binds AbstractVertexAttribute
else
- vao = new VertexAttributePreGL43(); // also binds VertexAttribute
+ vao = new VertexAttributePreGL43(); // also binds AbstractVertexAttribute
vao.bind();
// Now a pos+light.
- vao.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addUnsignedShortsPointer(4, false, true)); // 2+2+2+2
- //vao.setVertexAttribute(0, posAttrib, VertexAttribute.VertexPointer.addVec3Pointer(false)); // 4+4+4
- vao.setVertexAttribute(0, 1, VertexAttribute.VertexPointer.addUnsignedBytesPointer(4, true, false)); // +4
- //vao.setVertexAttribute(0, lightAttrib, VertexAttribute.VertexPointer.addUnsignedBytesPointer(2, false)); // +4 due to how it aligns
+ vao.setVertexAttribute(0, 0, VertexPointer.addUnsignedShortsPointer(4, false, true)); // 2+2+2+2
+ vao.setVertexAttribute(0, 1, VertexPointer.addUnsignedBytesPointer(4, true, false)); // +4
try
{
vao.completeAndCheck(vertexByteCount);
@@ -159,7 +158,7 @@ public class LodRenderProgram extends ShaderProgram
public void bindVertexBuffer(int vbo)
{
- vao.bindBufferToAllBindingPoint(vbo);
+ vao.bindBufferToAllBindingPoints(vbo);
}
public void unbindVertexBuffer()
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
index 24b614564..a526dfe62 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
@@ -46,6 +46,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL32;
import java.awt.*;
@@ -250,6 +251,12 @@ public class LodRenderer
if (!this.isSetupComplete)
{
this.setup();
+
+ // shouldn't normally happen, but just in case
+ if (!this.isSetupComplete)
+ {
+ return;
+ }
}
@@ -263,10 +270,10 @@ public class LodRenderer
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.colorTextureId);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D,
0,
- GL32.GL_RGB,
+ GL32.GL_RGBA8,
MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight(),
0,
- GL32.GL_RGB,
+ GL32.GL_RGBA,
GL32.GL_UNSIGNED_BYTE,
(ByteBuffer) null);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
@@ -404,7 +411,8 @@ public class LodRenderer
profiler.popPush("LOD Transparent");
GL32.glEnable(GL32.GL_BLEND);
- GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
+ GL32.glBlendEquation(GL32.GL_FUNC_ADD);
+ GL32.glBlendFunc(GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
this.bufferHandler.renderTransparent(this);
GL32.glDepthMask(true); // Apparently the depth mask state is stored in the FBO, so glState fails to restore it...
@@ -414,11 +422,21 @@ public class LodRenderer
drawLagSpikeCatcher.end("LodDraw");
+
+ //=============================//
+ // Apply to the MC FrameBuffer //
+ //=============================//
+
profiler.popPush("LOD Apply");
+ GLState dhApplyGlState = new GLState();
+
// Copy the LOD framebuffer to Minecraft's framebuffer
DhApplyShader.INSTANCE.render(partialTicks);
+ dhApplyGlState.restore();
+
+
//================//
@@ -457,6 +475,7 @@ public class LodRenderer
}
}
+ private static final Logger LOGGER = LogManager.getLogger();
//=================//
@@ -471,8 +490,9 @@ public class LodRenderer
EVENT_LOGGER.warn("Renderer setup called but it has already completed setup!");
return;
}
- if (!GLProxy.hasInstance())
+ if (GLProxy.getInstance() == null)
{
+ // shouldn't normally happen, but just in case
EVENT_LOGGER.warn("Renderer setup called but GLProxy has not yet been setup!");
return;
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/ScreenQuad.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/ScreenQuad.java
index aa3014b1b..c250d69d3 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/ScreenQuad.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/ScreenQuad.java
@@ -21,12 +21,17 @@ package com.seibel.distanthorizons.core.render.renderer;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
-import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.AbstractVertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+/**
+ * Renders a full-screen textured quad to the screen.
+ * Used in composite / deferred rendering (IE fog).
+ */
public class ScreenQuad
{
public static ScreenQuad INSTANCE = new ScreenQuad();
@@ -41,7 +46,7 @@ public class ScreenQuad
};
private GLVertexBuffer boxBuffer;
- private VertexAttribute va;
+ private AbstractVertexAttribute va;
private boolean init = false;
@@ -56,11 +61,11 @@ public class ScreenQuad
if (this.init) return;
this.init = true;
- this.va = VertexAttribute.create();
+ this.va = AbstractVertexAttribute.create();
this.va.bind();
// Pos
- this.va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
+ this.va.setVertexAttribute(0, 0, VertexPointer.addVec2Pointer(false));
this.va.completeAndCheck(Float.BYTES * 2);
// Framebuffer
@@ -71,8 +76,10 @@ public class ScreenQuad
{
this.init();
+ this.boxBuffer.bind();
+
this.va.bind();
- this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId());
+ this.va.bindBufferToAllBindingPoints(this.boxBuffer.getId());
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
}
@@ -88,4 +95,5 @@ public class ScreenQuad
this.boxBuffer.bind();
this.boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
}
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/TestRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/TestRenderer.java
index fd91d5dfa..2c871f892 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/TestRenderer.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/TestRenderer.java
@@ -28,7 +28,8 @@ import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
-import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.AbstractVertexAttribute;
+import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.apache.logging.log4j.LogManager;
@@ -52,7 +53,7 @@ public class TestRenderer
ShaderProgram basicShader;
GLVertexBuffer sameContextBuffer;
GLVertexBuffer sharedContextBuffer;
- VertexAttribute va;
+ AbstractVertexAttribute va;
boolean init = false;
public void init()
@@ -60,12 +61,12 @@ public class TestRenderer
if (init) return;
logger.info("init");
init = true;
- va = VertexAttribute.create();
+ va = AbstractVertexAttribute.create();
va.bind();
// Pos
- va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
+ va.setVertexAttribute(0, 0, VertexPointer.addVec2Pointer(false));
// Color
- va.setVertexAttribute(0, 1, VertexAttribute.VertexPointer.addVec4Pointer(false));
+ va.setVertexAttribute(0, 1, VertexPointer.addVec4Pointer(false));
va.completeAndCheck(Float.BYTES * 6);
basicShader = new ShaderProgram("shaders/test/vert.vert", "shaders/test/frag.frag",
"fragColor", new String[]{"vPosition", "color"});
@@ -123,13 +124,13 @@ public class TestRenderer
if (System.currentTimeMillis() % 2000 < 1000)
{
sameContextBuffer.bind();
- va.bindBufferToAllBindingPoint(sameContextBuffer.getId());
+ va.bindBufferToAllBindingPoints(sameContextBuffer.getId());
spamLogger.debug("same context buffer");
}
else
{
sameContextBuffer.bind();
- va.bindBufferToAllBindingPoint(sharedContextBuffer.getId());
+ va.bindBufferToAllBindingPoints(sharedContextBuffer.getId());
spamLogger.debug("shared context buffer");
}
// Render the square
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java
index a71e28362..6b8517197 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java
@@ -21,10 +21,13 @@ package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
-import com.seibel.distanthorizons.core.render.renderer.SSAORenderer;
import com.seibel.distanthorizons.core.render.renderer.ScreenQuad;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL32;
+import java.nio.ByteBuffer;
+
/**
* Copies {@link LodRenderer}'s currently active color and depth texture to Minecraft's framebuffer.
*/
@@ -32,10 +35,16 @@ public class DhApplyShader extends AbstractShaderRenderer
{
public static DhApplyShader INSTANCE = new DhApplyShader();
+ private static final Logger LOGGER = LogManager.getLogger();
+
// uniforms
public int gDhColorTextureUniform;
public int gDepthMapUniform;
+ public int tempFramebufferId;
+ public int tempColorTextureId;
+ public int tempDepthTextureId;
+
@Override
public void onInit()
@@ -49,18 +58,16 @@ public class DhApplyShader extends AbstractShaderRenderer
// uniform setup
this.gDhColorTextureUniform = this.shader.getUniformLocation("gDhColorTexture");
this.gDepthMapUniform = this.shader.getUniformLocation("gDhDepthTexture");
+
+ this.tempFramebufferId = GL32.glGenFramebuffers();
+ this.tempColorTextureId = GL32.glGenTextures();
+ this.tempDepthTextureId = GL32.glGenTextures();
+
}
@Override
protected void onApplyUniforms(float partialTicks)
{
- GL32.glActiveTexture(GL32.GL_TEXTURE0);
- GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveColorTextureId());
- GL32.glUniform1i(this.gDhColorTextureUniform, 0);
-
- GL32.glActiveTexture(GL32.GL_TEXTURE1);
- GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveDepthTextureId());
- GL32.glUniform1i(this.gDepthMapUniform, 1);
}
@@ -69,6 +76,8 @@ public class DhApplyShader extends AbstractShaderRenderer
// render //
//========//
+ private boolean texturesCreated = false;
+
@Override
protected void onRender()
{
@@ -77,10 +86,17 @@ public class DhApplyShader extends AbstractShaderRenderer
GL32.glEnable(GL32.GL_BLEND);
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GL32.glBlendFunc(GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
-
+
+ GL32.glActiveTexture(GL32.GL_TEXTURE0);
+ GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveColorTextureId());
+ GL32.glUniform1i(this.gDhColorTextureUniform, 0);
+
+ GL32.glActiveTexture(GL32.GL_TEXTURE1);
+ GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveDepthTextureId());
+ GL32.glUniform1i(this.gDepthMapUniform, 1);
+
// Copy to MC's framebuffer
- GL32.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, 0); // this framebuffer shouldn't be used since we are reading in from a texture instead
- GL32.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
+ GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
ScreenQuad.INSTANCE.render();
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java
index 79c1ccda6..f1dbe79ce 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/FogShader.java
@@ -151,8 +151,10 @@ public class FogShader extends AbstractShaderRenderer
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
+
GL32.glEnable(GL32.GL_BLEND);
- GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
+ GL32.glBlendEquation(GL32.GL_FUNC_ADD);
+ GL32.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE);
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, LodRenderer.getActiveColorTextureId());
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
index 2f831f649..c8ef5565e 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
@@ -235,7 +235,7 @@ public class RenderUtil
}
public static int getFarClipPlaneDistanceInBlocks()
{
- int lodChunkDist = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get();
+ int lodChunkDist = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get();
return lodChunkDist * LodUtil.CHUNK_WIDTH;
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessage.java
index 238e72fa9..eb21117fe 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessage.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/GLMessage.java
@@ -269,6 +269,11 @@ public final class GLMessage
*/
public GLMessage add(String str)
{
+ // TODO fix implementation for MC 1.20.2 and newer
+ // please see the incomplete GLMessageTest for an example as to how the message formats differ
+ if (true)
+ return null;
+
str = str.trim();
if (str.isEmpty())
return null;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java
index 9dcaf72e7..1b4dc969b 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/objects/quadTree/QuadTree.java
@@ -56,7 +56,7 @@ public class QuadTree
*/
public final byte treeMaxDetailLevel;
- private final int widthInBlocks; // diameterInBlocks
+ private final int diameterInBlocks; // diameterInBlocks
/** contain the actual data in the quad tree structure */
private final MovableGridRingList> topRingList;
@@ -68,18 +68,18 @@ public class QuadTree
/**
* Constructor of the quadTree
*
- * @param widthInBlocks equivalent to the distance between two opposing sides
+ * @param diameterInBlocks equivalent to the distance between the two opposing sides
*/
- public QuadTree(int widthInBlocks, DhBlockPos2D centerBlockPos, byte treeMaxDetailLevel)
+ public QuadTree(int diameterInBlocks, DhBlockPos2D centerBlockPos, byte treeMaxDetailLevel)
{
this.centerBlockPos = centerBlockPos;
- this.widthInBlocks = widthInBlocks;
+ this.diameterInBlocks = diameterInBlocks;
this.treeMaxDetailLevel = treeMaxDetailLevel;
// the min detail level must be greater than 0 (to prevent divide by 0 errors) and greater than the maximum detail level
- this.treeMinDetailLevel = (byte) Math.max(Math.max(1, this.treeMaxDetailLevel), MathUtil.log2(widthInBlocks));
+ this.treeMinDetailLevel = (byte) Math.max(Math.max(1, this.treeMaxDetailLevel), MathUtil.log2(diameterInBlocks));
- int halfSizeInRootNodes = Math.floorDiv(this.widthInBlocks, 2) / BitShiftUtil.powerOfTwo(this.treeMinDetailLevel);
+ int halfSizeInRootNodes = Math.floorDiv(this.diameterInBlocks, 2) / BitShiftUtil.powerOfTwo(this.treeMinDetailLevel);
halfSizeInRootNodes = halfSizeInRootNodes + 1; // always add 1 so nodes will always have a parent, even if the tree's center is offset from the root node grid
Pos2D ringListCenterPos = new Pos2D(
@@ -171,14 +171,14 @@ public class QuadTree
// check if the testPos is within the X,Z boundary of the tree
- DhBlockPos2D treeBlockCorner = this.centerBlockPos.add(new DhBlockPos2D(-this.widthInBlocks / 2, -this.widthInBlocks / 2));
+ DhBlockPos2D treeBlockCorner = this.centerBlockPos.add(new DhBlockPos2D(-this.diameterInBlocks / 2, -this.diameterInBlocks / 2));
DhLodPos treeCornerPos = new DhLodPos((byte) 0, treeBlockCorner.x, treeBlockCorner.z);
DhSectionPos inputSectionCorner = testPos.convertNewToDetailLevel((byte) 0);
DhLodPos inputCornerPos = new DhLodPos((byte) 0, inputSectionCorner.getX(), inputSectionCorner.getZ());
int inputBlockWidth = BitShiftUtil.powerOfTwo(testPos.getDetailLevel());
- return DoSquaresOverlap(treeCornerPos, this.widthInBlocks, inputCornerPos, inputBlockWidth);
+ return DoSquaresOverlap(treeCornerPos, this.diameterInBlocks, inputCornerPos, inputBlockWidth);
}
private static boolean DoSquaresOverlap(DhLodPos square1Min, int square1Width, DhLodPos square2Min, int square2Width)
{
@@ -368,7 +368,7 @@ public class QuadTree
// TODO comment, currently a tree will always have 9 root nodes, because the tree will grow all the way up to the top, if this is ever changed then these values must also change
public int ringListWidth() { return 3; }
public int ringListHalfWidth() { return 1; }
- public int diameterInBlocks() { return this.widthInBlocks; }
+ public int diameterInBlocks() { return this.diameterInBlocks; }
// public String getDebugString()
// {
@@ -384,7 +384,7 @@ public class QuadTree
// }
@Override
- public String toString() { return "center block: " + this.centerBlockPos + ", block width: " + this.widthInBlocks + ", detail level range: [" + this.treeMaxDetailLevel + "-" + this.treeMinDetailLevel + "], leaf #: " + this.leafNodeCount(); }
+ public String toString() { return "center block: " + this.centerBlockPos + ", block width: " + this.diameterInBlocks + ", detail level range: [" + this.treeMaxDetailLevel + "-" + this.treeMinDetailLevel + "], leaf #: " + this.leafNodeCount(); }
diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json
index c0b6f05f2..8a67548ce 100644
--- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json
+++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json
@@ -88,9 +88,9 @@
"Max Horizontal Resolution",
"distanthorizons.config.client.advanced.graphics.quality.maxHorizontalResolution.@tooltip":
"The maximum detail LODs are rendered at.\n\n§6Fastest:§r Chunk\n§6Fanciest:§r Block",
- "distanthorizons.config.client.advanced.graphics.quality.lodChunkRenderDistance":
- "LOD Render Distance",
- "distanthorizons.config.client.advanced.graphics.quality.lodChunkRenderDistance.@tooltip":
+ "distanthorizons.config.client.advanced.graphics.quality.lodChunkRenderDistanceRadius":
+ "LOD Render Distance Radius",
+ "distanthorizons.config.client.advanced.graphics.quality.lodChunkRenderDistanceRadius.@tooltip":
"Distant Horizons' render distance, measured in chunks. \n\nNote: this is a best effort number. \nThe render distance may be above or below this number \ndepending on your other graphic settings.",
"distanthorizons.config.client.advanced.graphics.quality.verticalQuality":
"Vertical Quality",