Merge branch distant-horizons-core:main into fix/close-db-file

This commit is contained in:
s809
2023-10-19 18:01:52 +00:00
28 changed files with 768 additions and 419 deletions
@@ -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) <br>
* 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. <br>
* 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 <br>
* 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 <br>
* Note: This argument should also be encoded in UTF-8
* <strong>args[0]</strong> the file path to delete. Should be encoded in UTF-8.
* <strong>args[1]</strong> 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();
}
}
}
}
@@ -54,7 +54,7 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
@Override
public IDhApiConfigValue<Integer> chunkRenderDistance()
{ return new DhApiConfigValue<Integer, Integer>(Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance); }
{ return new DhApiConfigValue<Integer, Integer>(Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius); }
@Override
public IDhApiConfigValue<Boolean> renderingEnabled()
@@ -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<EQualityPreset> qualityPresetSetting = new ConfigEntry.Builder<EQualityPreset>()
.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<Integer> lodChunkRenderDistance = new ConfigEntry.Builder<Integer>()
public static ConfigEntry<Integer> lodChunkRenderDistanceRadius = new ConfigEntry.Builder<Integer>()
.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<Boolean> enableAutoUpdater = new ConfigEntry.Builder<Boolean>()
.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<Integer> glContextMajorVersion = new ConfigEntry.Builder<Integer>()
// .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<Integer> glContextMinorVersion = new ConfigEntry.Builder<Integer>()
// .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<Integer> glContextMajorVersion = new ConfigEntry.Builder<Integer>()
.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<Integer> glContextMinorVersion = new ConfigEntry.Builder<Integer>()
.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<EGlProfileMode> glProfileMode = new ConfigEntry.Builder<EGlProfileMode>()
.set(EGlProfileMode.CORE)
@@ -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);
@@ -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();
}
}
}
@@ -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);
@@ -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);
}
}
@@ -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(); }
@@ -48,7 +48,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> 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<LodRenderSection> 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)
@@ -171,7 +171,20 @@ public class GLProxy
long potentialLodBuilderGlContext = 0;
GLCapabilities potentialLodBuilderGlCapabilities = null;
for (Pair<Integer, Integer> supportedGlVersion : SUPPORTED_GL_VERSIONS)
int majorGlVersion = Config.Client.Advanced.Debugging.OpenGl.glContextMajorVersion.get();
int minorGlVersion = Config.Client.Advanced.Debugging.OpenGl.glContextMinorVersion.get();
ArrayList<Pair<Integer, Integer>> glVersions = new ArrayList<>();
if (majorGlVersion != 0)
{
glVersions.add(new Pair<>(majorGlVersion, minorGlVersion));
}
else
{
glVersions.addAll(SUPPORTED_GL_VERSIONS);
}
for (Pair<Integer, Integer> 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;
@@ -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;
@@ -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);
@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
@@ -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. <br><br>
*
* 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);
}
}
@@ -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<Integer, TreeSet<Integer>> bindingPointsToIndexBuilder;
ArrayList<VertexPointer> pointersBuilder;
// This will bind VertexAttribute
//=============//
// constructor //
//=============//
/** This will bind the {@link AbstractVertexAttribute} */
public VertexAttributePreGL43()
{
super(); // also bind VertexAttribute
bindingPointsToIndexBuilder = new TreeMap<Integer, TreeSet<Integer>>();
pointersBuilder = new ArrayList<VertexPointer>();
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<Integer> intArray = bindingPointsToIndexBuilder.computeIfAbsent(bindingPoint, k -> new TreeSet<Integer>());
TreeSet<Integer> 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<Integer> set) -> {
bindingPointsToIndex[i] = new int[set.size()];
this.bindingPointsToIndexBuilder.forEach((Integer i, TreeSet<Integer> set) ->
{
this.bindingPointsToIndex[i] = new int[set.size()];
Iterator<Integer> 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]);
}
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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); }
}
@@ -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();
@@ -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()
@@ -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;
}
@@ -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);
}
}
@@ -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
@@ -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();
}
@@ -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());
@@ -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;
}
@@ -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;
@@ -56,7 +56,7 @@ public class QuadTree<T>
*/
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<QuadNode<T>> topRingList;
@@ -68,18 +68,18 @@ public class QuadTree<T>
/**
* 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<T>
// 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<T>
// 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<T>
// }
@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(); }
@@ -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",