Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ed50e5134 | |||
| b5e3e6867c | |||
| 3e04342148 | |||
| 6699b568df | |||
| 53bee4ad42 | |||
| 5d5e462221 | |||
| d9b924cfed | |||
| 8bd70d593c | |||
| 5597044604 | |||
| 5d7c043d06 | |||
| 4aac61b37f | |||
| 22460fa1f5 | |||
| 2d127c7d98 | |||
| 91e17c420a | |||
| 93f5a85cb5 | |||
| b275971486 | |||
| 1234ff4d28 | |||
| f9bd7e2daf | |||
| 8ec4e235eb | |||
| b8a59d0ef6 | |||
| e500143781 | |||
| 406468b54c | |||
| 6857300ae2 | |||
| 6775ee23c3 | |||
| 44645943e2 | |||
| f385c4a56b | |||
| 0cf5e6d594 | |||
| 7b5b8da0d2 | |||
| 851f2ccd06 | |||
| 6c40389c07 | |||
| fada9e4cf6 | |||
| 06198fdbb8 | |||
| 3158eed5a3 | |||
| d2ff4a5806 |
+4
-1
@@ -9,12 +9,15 @@ package com.seibel.distanthorizons.api.interfaces.data;
|
|||||||
* @version 2024-7-14
|
* @version 2024-7-14
|
||||||
* @since API 3.0.0
|
* @since API 3.0.0
|
||||||
*/
|
*/
|
||||||
public interface IDhApiTerrainDataCache
|
public interface IDhApiTerrainDataCache // TODO should this be AutoClosable?
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Removes any data that's currently stored in this cache.
|
* Removes any data that's currently stored in this cache.
|
||||||
* This cane be done to free up memory or invalidate
|
* This cane be done to free up memory or invalidate
|
||||||
* the cache so fresh data can be pulled in.
|
* the cache so fresh data can be pulled in.
|
||||||
|
* <br><br>
|
||||||
|
* This should be called before de-referencing this object
|
||||||
|
* so DH can handle any necessary cleanup for internal objects.
|
||||||
*/
|
*/
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public final class ModInfo
|
|||||||
public static final String NAME = "DistantHorizons";
|
public static final String NAME = "DistantHorizons";
|
||||||
/** Human-readable version of NAME */
|
/** Human-readable version of NAME */
|
||||||
public static final String READABLE_NAME = "Distant Horizons";
|
public static final String READABLE_NAME = "Distant Horizons";
|
||||||
public static final String VERSION = "2.3.0-b";
|
public static final String VERSION = "2.3.2-b";
|
||||||
/** Returns true if the current build is an unstable developer build, false otherwise. */
|
/** Returns true if the current build is an unstable developer build, false otherwise. */
|
||||||
public static final boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
|
public static final boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
|
||||||
|
|
||||||
|
|||||||
+18
-6
@@ -197,10 +197,10 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||||
|
|
||||||
|
|
||||||
if (!(apiDataCache instanceof DhApiTerrainDataCache))
|
// the data cache can be null, but must be our own implementation
|
||||||
|
if (apiDataCache != null
|
||||||
|
&& !(apiDataCache instanceof DhApiTerrainDataCache))
|
||||||
{
|
{
|
||||||
// custom level wrappers aren't supported,
|
|
||||||
// the API user must get a level wrapper from our code somewhere
|
|
||||||
return DhApiResult.createFail("Unsupported [" + IDhApiTerrainDataCache.class.getSimpleName() + "] implementation, only the core class [" + DhApiTerrainDataCache.class.getSimpleName() + "] is a valid parameter.");
|
return DhApiResult.createFail("Unsupported [" + IDhApiTerrainDataCache.class.getSimpleName() + "] implementation, only the core class [" + DhApiTerrainDataCache.class.getSimpleName() + "] is a valid parameter.");
|
||||||
}
|
}
|
||||||
DhApiTerrainDataCache dataCache = (DhApiTerrainDataCache) apiDataCache;
|
DhApiTerrainDataCache dataCache = (DhApiTerrainDataCache) apiDataCache;
|
||||||
@@ -226,10 +226,9 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
// get the data source //
|
// get the data source //
|
||||||
//=====================//
|
//=====================//
|
||||||
|
|
||||||
|
FullDataSourceV2 dataSource = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FullDataSourceV2 dataSource = null;
|
|
||||||
|
|
||||||
// try using the cached data if possible
|
// try using the cached data if possible
|
||||||
if (dataCache != null)
|
if (dataCache != null)
|
||||||
{
|
{
|
||||||
@@ -244,7 +243,12 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
{
|
{
|
||||||
return DhApiResult.createFail("Unable to find/generate any data at the " + DhSectionPos.class.getSimpleName() + " [" + DhSectionPos.toString(sectionPos) + "].");
|
return DhApiResult.createFail("Unable to find/generate any data at the " + DhSectionPos.class.getSimpleName() + " [" + DhSectionPos.toString(sectionPos) + "].");
|
||||||
}
|
}
|
||||||
dataCache.add(sectionPos, dataSource);
|
|
||||||
|
// save to the cache if present
|
||||||
|
if (dataCache != null)
|
||||||
|
{
|
||||||
|
dataCache.add(sectionPos, dataSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -316,6 +320,14 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
|||||||
LOGGER.error("Unexpected exception in getTerrainDataColumnArray. Error: [" + e.getMessage() + "]", e);
|
LOGGER.error("Unexpected exception in getTerrainDataColumnArray. Error: [" + e.getMessage() + "]", e);
|
||||||
return DhApiResult.createFail("Unexpected exception: [" + e.getMessage() + "].");
|
return DhApiResult.createFail("Unexpected exception: [" + e.getMessage() + "].");
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (dataCache == null
|
||||||
|
&& dataSource != null)
|
||||||
|
{
|
||||||
|
dataSource.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ public class SharedApi
|
|||||||
|
|
||||||
public static void setDhWorld(AbstractDhWorld newWorld)
|
public static void setDhWorld(AbstractDhWorld newWorld)
|
||||||
{
|
{
|
||||||
|
AbstractDhWorld oldWorld = currentWorld;
|
||||||
|
if (oldWorld != null)
|
||||||
|
{
|
||||||
|
oldWorld.close();
|
||||||
|
}
|
||||||
currentWorld = newWorld;
|
currentWorld = newWorld;
|
||||||
|
|
||||||
// starting and stopping the DataRenderTransformer is necessary to prevent attempting to
|
// starting and stopping the DataRenderTransformer is necessary to prevent attempting to
|
||||||
|
|||||||
@@ -1015,9 +1015,23 @@ public class Config
|
|||||||
public static class OpenGl
|
public static class OpenGl
|
||||||
{
|
{
|
||||||
public static ConfigEntry<Boolean> overrideVanillaGLLogger = new ConfigEntry.Builder<Boolean>()
|
public static ConfigEntry<Boolean> overrideVanillaGLLogger = new ConfigEntry.Builder<Boolean>()
|
||||||
.set(ModInfo.IS_DEV_BUILD)
|
.set(true)
|
||||||
.comment(""
|
.comment(""
|
||||||
+ "Requires a reboot to change. \n"
|
+ "Defines how OpenGL errors are handled. \n "
|
||||||
|
+ "Requires rebooting Minecraft to change. \n"
|
||||||
|
+ "Will catch OpenGL errors thrown by other mods. \n"
|
||||||
|
+ "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public static ConfigEntry<Boolean> onlyLogGlErrorsOnce = new ConfigEntry.Builder<Boolean>()
|
||||||
|
.set(true)
|
||||||
|
.comment(""
|
||||||
|
+ "If true each Open GL error will only be logged once. \n"
|
||||||
|
+ "Enabling this may cause some error logs to be missed. \n"
|
||||||
|
+ "Does nothing if overrideVanillaGLLogger is set to false. \n"
|
||||||
|
+ " \n"
|
||||||
|
+ "Generally this can be kept as 'true' to prevent log spam. \n"
|
||||||
|
+ "However, Please set this to 'false' if a developer needs your log to debug a GL issue. \n"
|
||||||
+ "")
|
+ "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -1281,7 +1295,7 @@ public class Config
|
|||||||
|
|
||||||
public static ConfigEntry<Integer> generationProgressDisplayIntervalInSeconds = new ConfigEntry.Builder<Integer>()
|
public static ConfigEntry<Integer> generationProgressDisplayIntervalInSeconds = new ConfigEntry.Builder<Integer>()
|
||||||
.setChatCommandName("generation.logInterval")
|
.setChatCommandName("generation.logInterval")
|
||||||
.setMinDefaultMax(1, 5, 60 * 60 * 4) // max = 4 hours
|
.setMinDefaultMax(1, 2, 60 * 60 * 4) // max = 4 hours
|
||||||
.comment(""
|
.comment(""
|
||||||
+ "How often should the distant generator progress be displayed? \n"
|
+ "How often should the distant generator progress be displayed? \n"
|
||||||
+ "")
|
+ "")
|
||||||
|
|||||||
@@ -328,7 +328,8 @@ public class DhLightingEngine
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relNeighbourBlockPos.getY() < neighbourChunk.getMinNonEmptyHeight() || relNeighbourBlockPos.getY() > neighbourChunk.getExclusiveMaxBuildHeight())
|
if (relNeighbourBlockPos.getY() < neighbourChunk.getMinNonEmptyHeight()
|
||||||
|
|| relNeighbourBlockPos.getY() >= neighbourChunk.getExclusiveMaxBuildHeight())
|
||||||
{
|
{
|
||||||
// the light pos is outside the chunk's min/max height,
|
// the light pos is outside the chunk's min/max height,
|
||||||
// this can happen if given a chunk that hasn't finished generating
|
// this can happen if given a chunk that hasn't finished generating
|
||||||
|
|||||||
@@ -258,7 +258,11 @@ public class ClientLevelModule implements Closeable, AbstractDataSourceHandler.I
|
|||||||
|
|
||||||
public void clearRenderCache()
|
public void clearRenderCache()
|
||||||
{
|
{
|
||||||
this.clientLevel.getClientLevelWrapper().clearBlockColorCache();
|
IClientLevelWrapper clientLevelWrapper = this.clientLevel.getClientLevelWrapper();
|
||||||
|
if (clientLevelWrapper != null)
|
||||||
|
{
|
||||||
|
clientLevelWrapper.clearBlockColorCache();
|
||||||
|
}
|
||||||
|
|
||||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||||
if (ClientRenderState != null && ClientRenderState.quadtree != null)
|
if (ClientRenderState != null && ClientRenderState.quadtree != null)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV
|
|||||||
import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataSourceProvider;
|
import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataSourceProvider;
|
||||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||||
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
||||||
|
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||||
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
|
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
|
||||||
@@ -47,6 +48,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrap
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -63,6 +65,9 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
protected static final ConfigBasedLogger NETWORK_LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||||
|
() -> Config.Common.Logging.logNetworkEvent.get());
|
||||||
|
|
||||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
|
||||||
public final ClientLevelModule clientside;
|
public final ClientLevelModule clientside;
|
||||||
@@ -159,7 +164,9 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
|||||||
|
|
||||||
try (FullDataSourceV2DTO dataSourceDto = this.networkState.fullDataPayloadReceiver.decodeDataSourceAndReleaseBuffer(message.payload))
|
try (FullDataSourceV2DTO dataSourceDto = this.networkState.fullDataPayloadReceiver.decodeDataSourceAndReleaseBuffer(message.payload))
|
||||||
{
|
{
|
||||||
if (!message.isSameLevelAs(this.levelWrapper))
|
boolean isSameLevel = message.isSameLevelAs(this.levelWrapper);
|
||||||
|
NETWORK_LOGGER.debug("Buffer {} isSameLevel: {}", message.payload.dtoBufferId, isSameLevel);
|
||||||
|
if (!isSameLevel)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -107,6 +108,7 @@ public class DhClientServerLevel extends AbstractDhServerLevel implements IDhCli
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public IClientLevelWrapper getClientLevelWrapper() { return MC_CLIENT.getWrappedClientLevel(); }
|
public IClientLevelWrapper getClientLevelWrapper() { return MC_CLIENT.getWrappedClientLevel(); }
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public interface IDhClientLevel extends IDhLevel
|
public interface IDhClientLevel extends IDhLevel
|
||||||
{
|
{
|
||||||
@@ -35,6 +36,7 @@ public interface IDhClientLevel extends IDhLevel
|
|||||||
|
|
||||||
int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block);
|
int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
IClientLevelWrapper getClientLevelWrapper();
|
IClientLevelWrapper getClientLevelWrapper();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ public class WorldGenModule implements Closeable
|
|||||||
remainingChunkCount += this.worldGenerationQueue.getQueuedChunkCount();
|
remainingChunkCount += this.worldGenerationQueue.getQueuedChunkCount();
|
||||||
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
|
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
|
||||||
|
|
||||||
String message = "DH Gen/Import: " + remainingChunkCountStr + " chunks left.";
|
String message = "DH is loading chunks. " + remainingChunkCountStr + " left.";
|
||||||
|
|
||||||
// show a message about how to disable progress logging if requested
|
// show a message about how to disable progress logging if requested
|
||||||
int msToShowDisableInstructions = Config.Common.WorldGenerator.generationProgressDisableMessageDisplayTimeInSeconds.get() * 1_000;
|
int msToShowDisableInstructions = Config.Common.WorldGenerator.generationProgressDisableMessageDisplayTimeInSeconds.get() * 1_000;
|
||||||
|
|||||||
+6
-4
@@ -69,19 +69,21 @@ public class FullDataPayloadReceiver implements AutoCloseable
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public FullDataSourceV2DTO decodeDataSourceAndReleaseBuffer(FullDataPayload msg)
|
public FullDataSourceV2DTO decodeDataSourceAndReleaseBuffer(FullDataPayload payload)
|
||||||
{
|
{
|
||||||
CompositeByteBuf compositeByteBuffer = this.buffersById.get(msg.dtoBufferId);
|
CompositeByteBuf compositeByteBuffer = this.buffersById.get(payload.dtoBufferId);
|
||||||
LodUtil.assertTrue(compositeByteBuffer != null);
|
LodUtil.assertTrue(compositeByteBuffer != null);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return INetworkObject.decodeToInstance(FullDataSourceV2DTO.CreateEmptyDataSourceForDecoding(), compositeByteBuffer);
|
FullDataSourceV2DTO dataSourceDto = INetworkObject.decodeToInstance(FullDataSourceV2DTO.CreateEmptyDataSourceForDecoding(), compositeByteBuffer);
|
||||||
|
LOGGER.debug("Buffer {} DTO: {}", payload.dtoBufferId, dataSourceDto);
|
||||||
|
return dataSourceDto;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// Releasing the buffer is handled by cache
|
// Releasing the buffer is handled by cache
|
||||||
this.buffersById.remove(msg.dtoBufferId);
|
this.buffersById.remove(payload.dtoBufferId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -510,10 +510,13 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
|||||||
{
|
{
|
||||||
// TODO memoization is needed for multiplayer, otherwise
|
// TODO memoization is needed for multiplayer, otherwise
|
||||||
// new retrieval requests won't be submitted.
|
// new retrieval requests won't be submitted.
|
||||||
// TODO why is that the case? Shouldn't the missing positions be un-changing?
|
// TODO why is that the case? Shouldn't the missing positions be un-changing?
|
||||||
|
// TODO setting this value to low can cause world gen to slow down significantly
|
||||||
|
// due to a race condition where the world gen thinks it is finished, but the results
|
||||||
|
// haven't been saved to file yet, causing the gen to fire again
|
||||||
this.missingGenerationPosFunc = Suppliers.memoizeWithExpiration(
|
this.missingGenerationPosFunc = Suppliers.memoizeWithExpiration(
|
||||||
() -> this.fullDataSourceProvider.getPositionsToRetrieve(this.pos),
|
() -> this.fullDataSourceProvider.getPositionsToRetrieve(this.pos),
|
||||||
15, TimeUnit.SECONDS);
|
10, TimeUnit.MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
LongArrayList missingGenerationPos = this.getMissingGenerationPos();
|
LongArrayList missingGenerationPos = this.getMissingGenerationPos();
|
||||||
|
|||||||
@@ -359,6 +359,7 @@ public class RenderBufferHandler implements AutoCloseable
|
|||||||
// debug wireframe setup //
|
// debug wireframe setup //
|
||||||
//=======================//
|
//=======================//
|
||||||
|
|
||||||
|
// TODO move this logic into LodRenderer so all the GL states can be handled there
|
||||||
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
|
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
|
||||||
if (renderWireframe)
|
if (renderWireframe)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ import com.seibel.distanthorizons.core.config.Config;
|
|||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.util.objects.GLMessage;
|
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
|
||||||
import com.seibel.distanthorizons.core.util.objects.GLMessageOutputStream;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import com.seibel.distanthorizons.coreapi.util.StringUtil;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
@@ -38,31 +38,28 @@ import org.lwjgl.opengl.GLCapabilities;
|
|||||||
import org.lwjgl.opengl.GLUtil;
|
import org.lwjgl.opengl.GLUtil;
|
||||||
|
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A singleton that holds references to different openGL contexts
|
* A singleton that holds references to different openGL contexts
|
||||||
* and GPU capabilities.
|
* and GPU capabilities.
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Helpful OpenGL resources:
|
|
||||||
* <p>
|
|
||||||
* https://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf <br>
|
|
||||||
* https://learnopengl.com/Advanced-OpenGL/Advanced-Data <br>
|
|
||||||
* https://www.slideshare.net/CassEveritt/approaching-zero-driver-overhead <br><br>
|
|
||||||
*
|
|
||||||
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br>
|
|
||||||
* https://stackoverflow.com/questions/63509735/massive-performance-loss-with-glmapbuffer <br><br>
|
|
||||||
*/
|
*/
|
||||||
public class GLProxy
|
public class GLProxy
|
||||||
{
|
{
|
||||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
|
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
|
||||||
() -> Config.Common.Logging.logRendererGLEvent.get());
|
() -> Config.Common.Logging.logRendererGLEvent.get());
|
||||||
|
|
||||||
|
public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static GLProxy instance = null;
|
private static GLProxy instance = null;
|
||||||
|
|
||||||
|
|
||||||
@@ -79,7 +76,29 @@ public class GLProxy
|
|||||||
|
|
||||||
private final EDhApiGpuUploadMethod preferredUploadMethod;
|
private final EDhApiGpuUploadMethod preferredUploadMethod;
|
||||||
|
|
||||||
public final GLMessage.Builder vanillaDebugMessageBuilder = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER;
|
public final GLMessageBuilder vanillaDebugMessageBuilder =
|
||||||
|
new GLMessageBuilder(
|
||||||
|
(type) ->
|
||||||
|
{
|
||||||
|
if (type == EGLMessageType.POP_GROUP)
|
||||||
|
return false;
|
||||||
|
else if (type == EGLMessageType.PUSH_GROUP)
|
||||||
|
return false;
|
||||||
|
else if (type == EGLMessageType.MARKER)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
(severity) ->
|
||||||
|
{
|
||||||
|
// notifications can generally be ignored (if they are logged at all)
|
||||||
|
if (severity == EGLMessageSeverity.NOTIFICATION)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -258,6 +277,7 @@ public class GLProxy
|
|||||||
// logging //
|
// logging //
|
||||||
//=========//
|
//=========//
|
||||||
|
|
||||||
|
/** this method is called on the render thread at the point of the GL Error */
|
||||||
private static void logMessage(GLMessage msg)
|
private static void logMessage(GLMessage msg)
|
||||||
{
|
{
|
||||||
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
|
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
|
||||||
@@ -268,44 +288,56 @@ public class GLProxy
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (msg.type == GLMessage.EType.ERROR || msg.type == GLMessage.EType.UNDEFINED_BEHAVIOR)
|
boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get();
|
||||||
|
String errorMessage = "GL ERROR [" + msg.id + "] from [" + msg.source + "]: [" + msg.message + "]"+(onlyLogOnce ? " this message will only be logged once" : "")+".";
|
||||||
|
if (onlyLogOnce
|
||||||
|
&& !LOGGED_GL_MESSAGES.add(errorMessage))
|
||||||
|
{
|
||||||
|
// this message has already been logged
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// create an exception so we get a stacktrace of where the message was triggered from
|
||||||
|
RuntimeException exception = new RuntimeException(errorMessage);
|
||||||
|
|
||||||
|
if (msg.type == EGLMessageType.ERROR || msg.type == EGLMessageType.UNDEFINED_BEHAVIOR)
|
||||||
{
|
{
|
||||||
// critical error
|
// critical error
|
||||||
|
|
||||||
GL_LOGGER.error("GL ERROR " + msg.id + " from " + msg.source + ": " + msg.message);
|
GL_LOGGER.error(exception.getMessage(), exception);
|
||||||
|
|
||||||
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
|
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("GL ERROR: " + msg);
|
// will probably crash the game,
|
||||||
|
// good for quickly checking if there's a problem while preventing log spam
|
||||||
|
throw exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// non-critical log
|
// non-critical log
|
||||||
|
|
||||||
GLMessage.ESeverity severity = msg.severity;
|
EGLMessageSeverity severity = msg.severity;
|
||||||
RuntimeException ex = new RuntimeException("GL MESSAGE: " + msg);
|
|
||||||
|
|
||||||
if (severity == null)
|
if (severity == null)
|
||||||
{
|
{
|
||||||
// just in case the message was malformed
|
// just in case the message was malformed
|
||||||
severity = GLMessage.ESeverity.LOW;
|
severity = EGLMessageSeverity.LOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (severity)
|
switch (severity)
|
||||||
{
|
{
|
||||||
case HIGH:
|
case HIGH:
|
||||||
GL_LOGGER.error("{}", ex);
|
GL_LOGGER.error(exception.getMessage(), exception);
|
||||||
break;
|
break;
|
||||||
case MEDIUM:
|
case MEDIUM:
|
||||||
GL_LOGGER.warn("{}", ex);
|
GL_LOGGER.warn(exception.getMessage(), exception);
|
||||||
break;
|
break;
|
||||||
case LOW:
|
case LOW:
|
||||||
GL_LOGGER.info("{}", ex);
|
GL_LOGGER.info(exception.getMessage(), exception);
|
||||||
break;
|
break;
|
||||||
case NOTIFICATION:
|
case NOTIFICATION:
|
||||||
GL_LOGGER.debug("{}", ex);
|
GL_LOGGER.debug(exception.getMessage(), exception);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class GLState
|
|||||||
public int vao;
|
public int vao;
|
||||||
public int vbo;
|
public int vbo;
|
||||||
public int ebo;
|
public int ebo;
|
||||||
public int[] fbo;
|
public int fbo;
|
||||||
public int texture2D;
|
public int texture2D;
|
||||||
/** IE: GL_TEXTURE0, GL_TEXTURE1, etc. */
|
/** IE: GL_TEXTURE0, GL_TEXTURE1, etc. */
|
||||||
public int activeTextureNumber;
|
public int activeTextureNumber;
|
||||||
@@ -57,10 +57,10 @@ public class GLState
|
|||||||
public boolean depth;
|
public boolean depth;
|
||||||
public boolean writeToDepthBuffer;
|
public boolean writeToDepthBuffer;
|
||||||
public int depthFunc;
|
public int depthFunc;
|
||||||
//public boolean stencil;
|
public boolean stencil;
|
||||||
//public int stencilFunc;
|
public int stencilFunc;
|
||||||
//public int stencilRef;
|
public int stencilRef;
|
||||||
//public int stencilMask;
|
public int stencilMask;
|
||||||
public int[] view;
|
public int[] view;
|
||||||
public boolean cull;
|
public boolean cull;
|
||||||
public int cullMode;
|
public int cullMode;
|
||||||
@@ -68,12 +68,7 @@ public class GLState
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public GLState()
|
public GLState() { this.saveState(); }
|
||||||
{
|
|
||||||
this.fbo = new int[FBO_MAX];
|
|
||||||
|
|
||||||
this.saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void saveState()
|
public void saveState()
|
||||||
{
|
{
|
||||||
@@ -82,7 +77,7 @@ public class GLState
|
|||||||
this.vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
|
this.vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
|
||||||
this.ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
|
this.ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
|
||||||
|
|
||||||
GL32.glGetIntegerv(GL32.GL_FRAMEBUFFER_BINDING, this.fbo);
|
this.fbo = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
|
||||||
|
|
||||||
this.texture2D = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
this.texture2D = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||||
this.activeTextureNumber = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE);
|
this.activeTextureNumber = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE);
|
||||||
@@ -101,9 +96,19 @@ public class GLState
|
|||||||
|
|
||||||
GLMC.glActiveTexture(this.activeTextureNumber);
|
GLMC.glActiveTexture(this.activeTextureNumber);
|
||||||
|
|
||||||
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
if (this.fbo != 0)
|
||||||
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
{
|
||||||
this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// attempting to get values from the default framebuffer can throw errors on Linux
|
||||||
|
this.frameBufferTexture0 = 0;
|
||||||
|
this.frameBufferTexture1 = 0;
|
||||||
|
this.frameBufferDepthTexture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
this.blend = GL32.glIsEnabled(GL32.GL_BLEND);
|
this.blend = GL32.glIsEnabled(GL32.GL_BLEND);
|
||||||
this.scissor = GL32.glIsEnabled(GL32.GL_SCISSOR_TEST);
|
this.scissor = GL32.glIsEnabled(GL32.GL_SCISSOR_TEST);
|
||||||
@@ -116,10 +121,10 @@ public class GLState
|
|||||||
this.depth = GL32.glIsEnabled(GL32.GL_DEPTH_TEST);
|
this.depth = GL32.glIsEnabled(GL32.GL_DEPTH_TEST);
|
||||||
this.writeToDepthBuffer = GL32.glGetInteger(GL32.GL_DEPTH_WRITEMASK) == GL32.GL_TRUE;
|
this.writeToDepthBuffer = GL32.glGetInteger(GL32.GL_DEPTH_WRITEMASK) == GL32.GL_TRUE;
|
||||||
this.depthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC);
|
this.depthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC);
|
||||||
//this.stencil = GL32.glIsEnabled(GL32.GL_STENCIL_TEST);
|
this.stencil = GL32.glIsEnabled(GL32.GL_STENCIL_TEST);
|
||||||
//this.stencilFunc = GL32.glGetInteger(GL32.GL_STENCIL_FUNC);
|
this.stencilFunc = GL32.glGetInteger(GL32.GL_STENCIL_FUNC);
|
||||||
//this.stencilRef = GL32.glGetInteger(GL32.GL_STENCIL_REF);
|
this.stencilRef = GL32.glGetInteger(GL32.GL_STENCIL_REF);
|
||||||
//this.stencilMask = GL32.glGetInteger(GL32.GL_STENCIL_VALUE_MASK);
|
this.stencilMask = GL32.glGetInteger(GL32.GL_STENCIL_VALUE_MASK);
|
||||||
this.view = new int[4];
|
this.view = new int[4];
|
||||||
GL32.glGetIntegerv(GL32.GL_VIEWPORT, this.view);
|
GL32.glGetIntegerv(GL32.GL_VIEWPORT, this.view);
|
||||||
this.cull = GL32.glIsEnabled(GL32.GL_CULL_FACE);
|
this.cull = GL32.glIsEnabled(GL32.GL_CULL_FACE);
|
||||||
@@ -131,38 +136,33 @@ public class GLState
|
|||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return "GLState{" +
|
return "GLState{" +
|
||||||
"program=" + this.program + ", vao=" + this.vao + ", vbo=" + this.vbo + ", ebo=" + this.ebo + ", fbo=" + this.fbo[0] +
|
"program=" + this.program + ", vao=" + this.vao + ", vbo=" + this.vbo + ", ebo=" + this.ebo + ", fbo=" + this.fbo +
|
||||||
", text=" + GLEnums.getString(this.texture2D) + "@" + this.activeTextureNumber + ", text0=" + GLEnums.getString(this.texture0) +
|
", text=" + GLEnums.getString(this.texture2D) + "@" + this.activeTextureNumber + ", text0=" + GLEnums.getString(this.texture0) +
|
||||||
", FB text0=" + this.frameBufferTexture0 +
|
", FB text0=" + this.frameBufferTexture0 +
|
||||||
", FB text1=" + this.frameBufferTexture1 +
|
", FB text1=" + this.frameBufferTexture1 +
|
||||||
", FB depth=" + this.frameBufferDepthTexture +
|
", FB depth=" + this.frameBufferDepthTexture +
|
||||||
", blend=" + this.blend + ", scissor=" + this.scissor + ", blendMode=" + GLEnums.getString(this.blendSrcColor) + "," + GLEnums.getString(this.blendDstColor) +
|
", blend=" + this.blend + ", scissor=" + this.scissor + ", blendMode=" + GLEnums.getString(this.blendSrcColor) + "," + GLEnums.getString(this.blendDstColor) +
|
||||||
", depth=" + this.depth +
|
", depth=" + this.depth +
|
||||||
//", depthFunc=" + GLEnums.getString(this.depthFunc) + ", stencil=" + this.stencil + ", stencilFunc=" +
|
", depthFunc=" + GLEnums.getString(this.depthFunc) + ", stencil=" + this.stencil +
|
||||||
//GLEnums.getString(this.stencilFunc) + ", stencilRef=" + this.stencilRef + ", stencilMask=" + this.stencilMask +
|
", stencilFunc=" + GLEnums.getString(this.stencilFunc) + ", stencilRef=" + this.stencilRef + ", stencilMask=" + this.stencilMask +
|
||||||
", view={x:" + this.view[0] + ", y:" + this.view[1] +
|
", view={x:" + this.view[0] + ", y:" + this.view[1] +
|
||||||
", w:" + this.view[2] + ", h:" + this.view[3] + "}" + ", cull=" + this.cull + ", cullMode="
|
", w:" + this.view[2] + ", h:" + this.view[3] + "}" + ", cull=" + this.cull +
|
||||||
+ GLEnums.getString(this.cullMode) + ", polyMode=" + GLEnums.getString(this.polyMode) +
|
", cullMode=" + GLEnums.getString(this.cullMode) + ", polyMode=" + GLEnums.getString(this.polyMode) +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RestoreFrameBuffer()
|
|
||||||
{
|
|
||||||
// explicitly unbinding the frame buffer is necessary to prevent GL_CLEAR calls from hitting the wrong buffer
|
|
||||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
for (int i = 0; i < FBO_MAX; i++)
|
|
||||||
{
|
|
||||||
int buffer = this.fbo[i];
|
|
||||||
if (i > 0 && buffer == 0) break;
|
|
||||||
|
|
||||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, GL32.glIsFramebuffer(buffer) ? buffer : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void restore()
|
public void restore()
|
||||||
{
|
{
|
||||||
this.RestoreFrameBuffer();
|
// explicitly unbinding the frame buffer is necessary to prevent GL_CLEAR calls from hitting the wrong buffer
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, 0);
|
||||||
|
boolean frameBufferSet = false;
|
||||||
|
|
||||||
|
if (this.fbo != 0 && GL32.glIsFramebuffer(this.fbo))
|
||||||
|
{
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fbo);
|
||||||
|
frameBufferSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.blend)
|
if (this.blend)
|
||||||
{
|
{
|
||||||
@@ -197,9 +197,13 @@ public class GLState
|
|||||||
GLMC.glActiveTexture(this.activeTextureNumber);
|
GLMC.glActiveTexture(this.activeTextureNumber);
|
||||||
GLMC.glBindTexture(GL32.glIsTexture(this.texture2D) ? this.texture2D : 0);
|
GLMC.glBindTexture(GL32.glIsTexture(this.texture2D) ? this.texture2D : 0);
|
||||||
|
|
||||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
|
// attempting to set textures on the default frame buffer (ID 0) will throw errors
|
||||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
|
if (frameBufferSet)
|
||||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
|
{
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
|
||||||
|
}
|
||||||
|
|
||||||
GL32.glBindVertexArray(GL32.glIsVertexArray(this.vao) ? this.vao : 0);
|
GL32.glBindVertexArray(GL32.glIsVertexArray(this.vao) ? this.vao : 0);
|
||||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(this.vbo) ? this.vbo : 0);
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(this.vbo) ? this.vbo : 0);
|
||||||
@@ -229,15 +233,15 @@ public class GLState
|
|||||||
}
|
}
|
||||||
GLMC.glDepthFunc(this.depthFunc);
|
GLMC.glDepthFunc(this.depthFunc);
|
||||||
|
|
||||||
//if (this.stencil)
|
if (this.stencil)
|
||||||
//{
|
{
|
||||||
// GL32.glEnable(GL32.GL_STENCIL_TEST);
|
GL32.glEnable(GL32.GL_STENCIL_TEST);
|
||||||
//}
|
}
|
||||||
//else
|
else
|
||||||
//{
|
{
|
||||||
// GL32.glDisable(GL32.GL_STENCIL_TEST);
|
GL32.glDisable(GL32.GL_STENCIL_TEST);
|
||||||
//}
|
}
|
||||||
//GL32.glStencilFunc(this.stencilFunc, this.stencilRef, this.stencilMask);
|
GL32.glStencilFunc(this.stencilFunc, this.stencilRef, this.stencilMask);
|
||||||
|
|
||||||
GL32.glViewport(this.view[0], this.view[1], this.view[2], this.view[3]);
|
GL32.glViewport(this.view[0], this.view[1], this.view[2], this.view[3]);
|
||||||
if (this.cull)
|
if (this.cull)
|
||||||
|
|||||||
+1
-1
@@ -223,7 +223,7 @@ public class GLBuffer implements AutoCloseable
|
|||||||
this.destroyAsync();
|
this.destroyAsync();
|
||||||
this.create(true);
|
this.create(true);
|
||||||
this.bind();
|
this.bind();
|
||||||
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, bufferStorageHint);
|
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, 0);
|
||||||
this.size = bbSize;
|
this.size = bbSize;
|
||||||
}
|
}
|
||||||
/** Requires the buffer to be bound */
|
/** Requires the buffer to be bound */
|
||||||
|
|||||||
+46
-27
@@ -32,15 +32,18 @@ import org.lwjgl.opengl.GL32;
|
|||||||
/**
|
/**
|
||||||
* This object holds a OpenGL reference to a shader
|
* This object holds a OpenGL reference to a shader
|
||||||
* and allows for reading in and compiling a shader file.
|
* and allows for reading in and compiling a shader file.
|
||||||
*
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 11-8-2021
|
|
||||||
*/
|
*/
|
||||||
public class Shader
|
public class Shader
|
||||||
{
|
{
|
||||||
/** OpenGL shader ID */
|
/** OpenGL shader ID */
|
||||||
public final int id;
|
public final int id;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a shader with specified type.
|
* Creates a shader with specified type.
|
||||||
*
|
*
|
||||||
@@ -51,51 +54,67 @@ public class Shader
|
|||||||
*/
|
*/
|
||||||
public Shader(int type, String path, boolean absoluteFilePath)
|
public Shader(int type, String path, boolean absoluteFilePath)
|
||||||
{
|
{
|
||||||
GLProxy.GL_LOGGER.info("Loading shader at " + path);
|
GLProxy.GL_LOGGER.info("Loading shader at [" + path + "]");
|
||||||
// Create an empty shader object
|
// Create an empty shader object
|
||||||
id = GL32.glCreateShader(type);
|
this.id = GL32.glCreateShader(type);
|
||||||
StringBuilder source = loadFile(path, absoluteFilePath, new StringBuilder());
|
if (this.id == 0)
|
||||||
GL32.glShaderSource(id, source);
|
{
|
||||||
|
throw new IllegalArgumentException("Failed to create shader with type ["+type+"].");
|
||||||
|
}
|
||||||
|
|
||||||
GL32.glCompileShader(id);
|
StringBuilder source = loadFile(path, absoluteFilePath, new StringBuilder());
|
||||||
|
GL32.glShaderSource(this.id, source);
|
||||||
|
|
||||||
|
GL32.glCompileShader(this.id);
|
||||||
// check if the shader compiled
|
// check if the shader compiled
|
||||||
int status = GL32.glGetShaderi(id, GL32.GL_COMPILE_STATUS);
|
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
|
||||||
if (status != GL32.GL_TRUE)
|
if (status != GL32.GL_TRUE)
|
||||||
{
|
{
|
||||||
String message = "Shader compiler error. Details: " + GL32.glGetShaderInfoLog(id);
|
String message = "Shader compiler error. Details: ["+GL32.glGetShaderInfoLog(this.id)+"].";
|
||||||
free(); // important!
|
this.free(); // important!
|
||||||
throw new RuntimeException(message);
|
throw new RuntimeException(message);
|
||||||
}
|
}
|
||||||
GLProxy.GL_LOGGER.info("Shader at " + path + " loaded sucessfully.");
|
GLProxy.GL_LOGGER.info("Shader at " + path + " loaded successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Shader(int type, String sourceString)
|
public Shader(int type, String sourceString)
|
||||||
{
|
{
|
||||||
GLProxy.GL_LOGGER.info("Loading shader with type: {}", type);
|
GLProxy.GL_LOGGER.info("Loading shader with type: ["+type+"]");
|
||||||
GLProxy.GL_LOGGER.debug("Source:\n{}", sourceString);
|
GLProxy.GL_LOGGER.debug("Source: \n["+sourceString+"]");
|
||||||
// Create an empty shader object
|
if (sourceString == null || sourceString.isEmpty())
|
||||||
id = GL32.glCreateShader(type);
|
{
|
||||||
GL32.glShaderSource(id, sourceString);
|
throw new IllegalArgumentException("No shader source given.");
|
||||||
|
}
|
||||||
|
|
||||||
GL32.glCompileShader(id);
|
// Create an empty shader object
|
||||||
|
this.id = GL32.glCreateShader(type);
|
||||||
|
if (this.id == 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Failed to create shader with type ["+type+"] and Source: \n["+sourceString+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
GL32.glShaderSource(this.id, sourceString);
|
||||||
|
GL32.glCompileShader(this.id);
|
||||||
// check if the shader compiled
|
// check if the shader compiled
|
||||||
int status = GL32.glGetShaderi(id, GL32.GL_COMPILE_STATUS);
|
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
|
||||||
if (status != GL32.GL_TRUE)
|
if (status != GL32.GL_TRUE)
|
||||||
{
|
{
|
||||||
|
|
||||||
String message = "Shader compiler error. Details: " + GL32.glGetShaderInfoLog(id);
|
String message = "Shader compiler error. Details: [" + GL32.glGetShaderInfoLog(this.id) + "]\n";
|
||||||
message += "\nSource:\n" + sourceString;
|
message += "Source: \n[" + sourceString + "]";
|
||||||
free(); // important!
|
this.free(); // important!
|
||||||
throw new RuntimeException(message);
|
throw new RuntimeException(message);
|
||||||
}
|
}
|
||||||
GLProxy.GL_LOGGER.info("Shader loaded sucessfully.");
|
GLProxy.GL_LOGGER.info("Shader loaded sucessfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// REMEMBER to always free the resource!
|
|
||||||
public void free()
|
|
||||||
{
|
//=========//
|
||||||
GL32.glDeleteShader(id);
|
// helpers //
|
||||||
}
|
//=========//
|
||||||
|
|
||||||
|
public void free() { GL32.glDeleteShader(this.id); }
|
||||||
|
|
||||||
public static StringBuilder loadFile(String path, boolean absoluteFilePath, StringBuilder stringBuilder)
|
public static StringBuilder loadFile(String path, boolean absoluteFilePath, StringBuilder stringBuilder)
|
||||||
{
|
{
|
||||||
|
|||||||
+28
-14
@@ -86,22 +86,31 @@ public class FadeRenderer
|
|||||||
this.fadeFramebuffer = -1;
|
this.fadeFramebuffer = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.fadeTexture != -1)
|
|
||||||
{
|
|
||||||
GLMC.glDeleteTextures(this.fadeTexture);
|
|
||||||
this.fadeTexture = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fadeFramebuffer = GL32.glGenFramebuffers();
|
this.fadeFramebuffer = GL32.glGenFramebuffers();
|
||||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer);
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer);
|
||||||
|
|
||||||
this.fadeTexture = GL32.glGenTextures();
|
|
||||||
GLMC.glBindTexture(this.fadeTexture);
|
|
||||||
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
|
||||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0);
|
|
||||||
|
|
||||||
|
// Applying the fade texture is only needed if MC is drawing to their own frame buffer,
|
||||||
|
// otherwise we can directly render to their texture
|
||||||
|
if (MC_RENDER.mcRendersToFrameBuffer())
|
||||||
|
{
|
||||||
|
if (this.fadeTexture != -1)
|
||||||
|
{
|
||||||
|
GLMC.glDeleteTextures(this.fadeTexture);
|
||||||
|
this.fadeTexture = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fadeTexture = GL32.glGenTextures();
|
||||||
|
GLMC.glBindTexture(this.fadeTexture);
|
||||||
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, MC_RENDER.getColorTextureId(), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -146,8 +155,13 @@ public class FadeRenderer
|
|||||||
|
|
||||||
profiler.popPush("Fade Apply");
|
profiler.popPush("Fade Apply");
|
||||||
|
|
||||||
FadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
|
// Applying the fade texture is only needed if MC is drawing to their own frame buffer,
|
||||||
FadeApplyShader.INSTANCE.render(partialTicks);
|
// otherwise we can directly render to their texture
|
||||||
|
if (MC_RENDER.mcRendersToFrameBuffer())
|
||||||
|
{
|
||||||
|
FadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
|
||||||
|
FadeApplyShader.INSTANCE.render(partialTicks);
|
||||||
|
}
|
||||||
|
|
||||||
profiler.pop();
|
profiler.pop();
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-40
@@ -557,34 +557,24 @@ public class LodRenderer
|
|||||||
activeFrameBuffer.bind();
|
activeFrameBuffer.bind();
|
||||||
|
|
||||||
|
|
||||||
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderEventParam);
|
|
||||||
if (clearTextures)
|
|
||||||
{
|
|
||||||
if (this.usingMcFrameBuffer && framebufferOverride == null)
|
|
||||||
{
|
|
||||||
// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
|
|
||||||
// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
|
|
||||||
activeFrameBuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
|
||||||
|
|
||||||
|
|
||||||
// don't clear the color texture, that removes the sky
|
|
||||||
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
else if (firstPass)
|
|
||||||
{
|
|
||||||
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// by default draw everything as triangles
|
// by default draw everything as triangles
|
||||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||||
GLMC.enableFaceCulling();
|
GLMC.enableFaceCulling();
|
||||||
|
|
||||||
|
GLMC.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ZERO);
|
||||||
|
|
||||||
|
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||||
|
|
||||||
// Enable depth test and depth mask
|
// Enable depth test and depth mask
|
||||||
GLMC.enableDepthTest();
|
GLMC.enableDepthTest();
|
||||||
GLMC.glDepthFunc(GL32.GL_LESS);
|
GLMC.glDepthFunc(GL32.GL_LESS);
|
||||||
GLMC.enableDepthMask();
|
GLMC.enableDepthMask();
|
||||||
|
|
||||||
|
// This is required for MC versions 1.21.5+
|
||||||
|
// due to MC updating the lightmap by changing the viewport size
|
||||||
|
GL32.glViewport(0, 0, this.cachedWidth, this.cachedHeight);
|
||||||
|
|
||||||
/*---------Bind required objects--------*/
|
/*---------Bind required objects--------*/
|
||||||
// Setup LodRenderProgram and the LightmapTexture if it has not yet been done
|
// Setup LodRenderProgram and the LightmapTexture if it has not yet been done
|
||||||
// also binds LightmapTexture, VAO, and ShaderProgram
|
// also binds LightmapTexture, VAO, and ShaderProgram
|
||||||
@@ -605,6 +595,33 @@ public class LodRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.lodRenderProgram.fillUniformData(renderEventParam);
|
this.lodRenderProgram.fillUniformData(renderEventParam);
|
||||||
|
|
||||||
|
|
||||||
|
// needs to be fired after all the textures have been created/bound
|
||||||
|
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderEventParam);
|
||||||
|
if (clearTextures)
|
||||||
|
{
|
||||||
|
GL32.glClearDepth(1.0);
|
||||||
|
|
||||||
|
float[] clearColorValues = new float[4];
|
||||||
|
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
|
||||||
|
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
|
||||||
|
|
||||||
|
if (this.usingMcFrameBuffer && framebufferOverride == null)
|
||||||
|
{
|
||||||
|
// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
|
||||||
|
// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
|
||||||
|
activeFrameBuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||||
|
|
||||||
|
|
||||||
|
// don't clear the color texture, that removes the sky
|
||||||
|
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
else if (firstPass)
|
||||||
|
{
|
||||||
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Setup all render objects - MUST be called on the render thread */
|
/** Setup all render objects - MUST be called on the render thread */
|
||||||
@@ -656,7 +673,7 @@ public class LodRenderer
|
|||||||
if(this.framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE)
|
if(this.framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE)
|
||||||
{
|
{
|
||||||
// This generally means something wasn't bound, IE missing either the color or depth texture
|
// This generally means something wasn't bound, IE missing either the color or depth texture
|
||||||
SPAM_LOGGER.warn("FrameBuffer ["+this.framebuffer.getId()+"] isn't complete.");
|
EVENT_LOGGER.warn("FrameBuffer ["+this.framebuffer.getId()+"] isn't complete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -716,25 +733,6 @@ public class LodRenderer
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Color getFogColor(float partialTicks)
|
|
||||||
{
|
|
||||||
Color fogColor;
|
|
||||||
|
|
||||||
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EDhApiFogColorMode.USE_SKY_COLOR)
|
|
||||||
{
|
|
||||||
fogColor = MC_RENDER.getSkyColor();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fogColor = MC_RENDER.getFogColor(partialTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fogColor;
|
|
||||||
}
|
|
||||||
private Color getSpecialFogColor(float partialTicks) { return MC_RENDER.getSpecialFogColor(partialTicks); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===============//
|
//===============//
|
||||||
// API functions //
|
// API functions //
|
||||||
//===============//
|
//===============//
|
||||||
@@ -748,7 +746,10 @@ public class LodRenderer
|
|||||||
public static int getActiveColorTextureId() { return activeColorTextureId; }
|
public static int getActiveColorTextureId() { return activeColorTextureId; }
|
||||||
|
|
||||||
private void setActiveDepthTextureId(int depthTextureId) { activeDepthTextureId = depthTextureId; }
|
private void setActiveDepthTextureId(int depthTextureId) { activeDepthTextureId = depthTextureId; }
|
||||||
/** Returns -1 if no texture has been bound yet */
|
/**
|
||||||
|
* FIXME it's possible for this to return an invalid texture ID if the renderer is being re-built at the same time
|
||||||
|
* Returns -1 if no texture has been bound yet
|
||||||
|
*/
|
||||||
public static int getActiveDepthTextureId() { return activeDepthTextureId; }
|
public static int getActiveDepthTextureId() { return activeDepthTextureId; }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+82
-3
@@ -75,6 +75,18 @@ public class DhApplyShader extends AbstractShaderRenderer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRender()
|
protected void onRender()
|
||||||
|
{
|
||||||
|
if (MC_RENDER.mcRendersToFrameBuffer())
|
||||||
|
{
|
||||||
|
this.renderToFrameBuffer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.renderToMcTexture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO merge duplicate code between these to render methods
|
||||||
|
private void renderToFrameBuffer()
|
||||||
{
|
{
|
||||||
int targetFrameBuffer = MC_RENDER.getTargetFrameBuffer();
|
int targetFrameBuffer = MC_RENDER.getTargetFrameBuffer();
|
||||||
if (targetFrameBuffer == -1)
|
if (targetFrameBuffer == -1)
|
||||||
@@ -87,9 +99,15 @@ public class DhApplyShader extends AbstractShaderRenderer
|
|||||||
|
|
||||||
GLMC.disableDepthTest();
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
GLMC.enableBlend();
|
// blending isn't needed, we're manually merging the MC and DH textures
|
||||||
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
|
// Note: this prevents the sun/moon and stars from rendering through transparent LODs,
|
||||||
GLMC.glBlendFunc(GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
// however this also fixes transparent LODs from glowing when rendered against the sky during the day
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
// old blending logic in case it's ever needed:
|
||||||
|
//GLMC.enableBlend();
|
||||||
|
//GL32.glBlendEquation(GL32.GL_FUNC_ADD);
|
||||||
|
//GLMC.glBlendFunc(GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
GLMC.glBindTexture(LodRenderer.getActiveColorTextureId());
|
GLMC.glBindTexture(LodRenderer.getActiveColorTextureId());
|
||||||
@@ -110,5 +128,66 @@ public class DhApplyShader extends AbstractShaderRenderer
|
|||||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, targetFrameBuffer);
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, targetFrameBuffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
private void renderToMcTexture()
|
||||||
|
{
|
||||||
|
int targetColorTextureId = MC_RENDER.getColorTextureId();
|
||||||
|
if (targetColorTextureId == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dhFrameBufferId = LodRenderer.getActiveFramebufferId();
|
||||||
|
if (dhFrameBufferId == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mcFrameBufferId = MC_RENDER.getTargetFrameBuffer();
|
||||||
|
if (mcFrameBufferId == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GLState state = new GLState();
|
||||||
|
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
|
// blending isn't needed, we're just directly merging the MC and DH textures
|
||||||
|
// Note: this prevents the sun/moon and stars from rendering through transparent LODs,
|
||||||
|
// however this also fixes
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
// old blending logic in case it's ever needed:
|
||||||
|
//GLMC.enableBlend();
|
||||||
|
//GL32.glBlendEquation(GL32.GL_FUNC_ADD);
|
||||||
|
//GLMC.glBlendFunc(GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(LodRenderer.getActiveColorTextureId());
|
||||||
|
GL32.glUniform1i(this.gDhColorTextureUniform, 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(LodRenderer.getActiveDepthTextureId());
|
||||||
|
GL32.glUniform1i(this.gDepthMapUniform, 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GL32.glFramebufferTexture(GL32.GL_DRAW_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, targetColorTextureId, 0);
|
||||||
|
|
||||||
|
// Copy to MC's texture via MC's framebuffer
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, dhFrameBufferId);
|
||||||
|
|
||||||
|
ScreenQuad.INSTANCE.render();
|
||||||
|
|
||||||
|
|
||||||
|
// restore everything, except at this point the MC framebuffer should now be used instead
|
||||||
|
state.restore();
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, mcFrameBufferId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -20,6 +20,7 @@
|
|||||||
package com.seibel.distanthorizons.core.render.renderer.shaders;
|
package com.seibel.distanthorizons.core.render.renderer.shaders;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.render.glObject.GLState;
|
||||||
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
|
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
|
||||||
import com.seibel.distanthorizons.core.render.renderer.FadeRenderer;
|
import com.seibel.distanthorizons.core.render.renderer.FadeRenderer;
|
||||||
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
||||||
@@ -104,6 +105,12 @@ public class FadeApplyShader extends AbstractShaderRenderer
|
|||||||
@Override
|
@Override
|
||||||
protected void onRender()
|
protected void onRender()
|
||||||
{
|
{
|
||||||
|
if (!MC_RENDER.mcRendersToFrameBuffer())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("If Minecraft is directly rendering to a texture the apply shader isn't needed, just draw the fade directly to the MC color texture.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GLMC.disableBlend();
|
GLMC.disableBlend();
|
||||||
|
|
||||||
// Depth testing must be disabled otherwise this application shader won't apply anything.
|
// Depth testing must be disabled otherwise this application shader won't apply anything.
|
||||||
@@ -119,6 +126,9 @@ public class FadeApplyShader extends AbstractShaderRenderer
|
|||||||
ScreenQuad.INSTANCE.render();
|
ScreenQuad.INSTANCE.render();
|
||||||
|
|
||||||
GLMC.enableDepthTest();
|
GLMC.enableDepthTest();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -165,6 +165,7 @@ public class FadeShader extends AbstractShaderRenderer
|
|||||||
GL32.glUniform1i(this.uMcDepthTexture, 0);
|
GL32.glUniform1i(this.uMcDepthTexture, 0);
|
||||||
|
|
||||||
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
// FIXME it's possible for this to return an invalid texture ID if the renderer is being re-built at the same time
|
||||||
GLMC.glBindTexture(LodRenderer.getActiveDepthTextureId());
|
GLMC.glBindTexture(LodRenderer.getActiveDepthTextureId());
|
||||||
GL32.glUniform1i(this.uDhDepthTexture, 1);
|
GL32.glUniform1i(this.uDhDepthTexture, 1);
|
||||||
|
|
||||||
|
|||||||
+1
@@ -84,6 +84,7 @@ public class FogApplyShader extends AbstractShaderRenderer
|
|||||||
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
GLMC.glBindTexture(LodRenderer.getActiveDepthTextureId());
|
GLMC.glBindTexture(LodRenderer.getActiveDepthTextureId());
|
||||||
GL32.glUniform1i(this.depthTextureUniform, 1);
|
GL32.glUniform1i(this.depthTextureUniform, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+15
-2
@@ -28,9 +28,11 @@ import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
|
|||||||
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
||||||
import com.seibel.distanthorizons.core.render.renderer.ScreenQuad;
|
import com.seibel.distanthorizons.core.render.renderer.ScreenQuad;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
import org.lwjgl.opengl.GL32;
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
@@ -41,11 +43,14 @@ public class FogShader extends AbstractShaderRenderer
|
|||||||
|
|
||||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
|
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public int frameBuffer;
|
public int frameBuffer;
|
||||||
|
|
||||||
private Mat4f inverseMvmProjMatrix;
|
private Mat4f inverseMvmProjMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========//
|
//==========//
|
||||||
@@ -253,7 +258,15 @@ public class FogShader extends AbstractShaderRenderer
|
|||||||
|
|
||||||
// this is necessary for MC 1.16 (IE Legacy OpenGL)
|
// this is necessary for MC 1.16 (IE Legacy OpenGL)
|
||||||
// otherwise the framebuffer isn't cleared correctly and the fog smears across the screen
|
// otherwise the framebuffer isn't cleared correctly and the fog smears across the screen
|
||||||
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
if (MC_RENDER.runningLegacyOpenGL())
|
||||||
|
{
|
||||||
|
// in another part of the DH code we set the fog color to opaque, here it needs to be transparent
|
||||||
|
float[] clearColorValues = new float[4];
|
||||||
|
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
|
||||||
|
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 0.0f);
|
||||||
|
|
||||||
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ScreenQuad.INSTANCE.render();
|
ScreenQuad.INSTANCE.render();
|
||||||
|
|||||||
-3
@@ -134,9 +134,6 @@ public class SSAOApplyShader extends AbstractShaderRenderer
|
|||||||
// it should be automatically restored after rendering is complete.
|
// it should be automatically restored after rendering is complete.
|
||||||
GLMC.disableDepthTest();
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
|
||||||
GLMC.glBindTexture(0);
|
|
||||||
|
|
||||||
// apply the rendered SSAO to the LODs
|
// apply the rendered SSAO to the LODs
|
||||||
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, SSAOShader.INSTANCE.frameBuffer);
|
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, SSAOShader.INSTANCE.frameBuffer);
|
||||||
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, LodRenderer.getActiveFramebufferId());
|
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, LodRenderer.getActiveFramebufferId());
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ public class FullDataSourceV2DTO
|
|||||||
{
|
{
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
.add("levelMinY", this.levelMinY)
|
.add("levelMinY", this.levelMinY)
|
||||||
.add("pos", this.pos)
|
.add("pos", DhSectionPos.toString(this.pos))
|
||||||
.add("dataChecksum", this.dataChecksum)
|
.add("dataChecksum", this.dataChecksum)
|
||||||
.add("compressedDataByteArray length", this.compressedDataByteArray.size())
|
.add("compressedDataByteArray length", this.compressedDataByteArray.size())
|
||||||
.add("compressedColumnGenStepByteArray length", this.compressedColumnGenStepByteArray.size())
|
.add("compressedColumnGenStepByteArray length", this.compressedColumnGenStepByteArray.size())
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.seibel.distanthorizons.core.sql.DbConnectionClosedException;
|
|||||||
import com.seibel.distanthorizons.core.sql.dto.IBaseDTO;
|
import com.seibel.distanthorizons.core.sql.dto.IBaseDTO;
|
||||||
import com.seibel.distanthorizons.core.sql.repo.phantoms.AutoClosableTrackingWrapper;
|
import com.seibel.distanthorizons.core.sql.repo.phantoms.AutoClosableTrackingWrapper;
|
||||||
import com.seibel.distanthorizons.core.util.KeyedLockContainer;
|
import com.seibel.distanthorizons.core.util.KeyedLockContainer;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -501,7 +502,12 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOGGER.warn("Attempting to close already closed database connection: [" + connectionString + "]");
|
// these warnings can be ignored in release builds, as long as the connection is closed it doesn't really matter
|
||||||
|
// TODO fix duplicate closes
|
||||||
|
if (ModInfo.IS_DEV_BUILD)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Attempting to close already closed database connection: [" + connectionString + "]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,7 +568,12 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOGGER.warn("Attempting to close already closed database connection: [" + this.connectionString + "]");
|
// these warnings can be ignored in release builds, as long as the connection is closed it doesn't really matter
|
||||||
|
// TODO fix duplicate closes
|
||||||
|
if (ModInfo.IS_DEV_BUILD)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Attempting to close already closed database connection: [" + this.connectionString + "]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ACTIVE_CONNECTION_STRINGS_BY_REPO.remove(this);
|
ACTIVE_CONNECTION_STRINGS_BY_REPO.remove(this);
|
||||||
|
|||||||
@@ -1,430 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU 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.util.objects;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles parsing and creating string messages from OpenGL messages.
|
|
||||||
*
|
|
||||||
* @author Leetom
|
|
||||||
* @version 2022-10-1
|
|
||||||
*/
|
|
||||||
public final class GLMessage
|
|
||||||
{
|
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
|
||||||
|
|
||||||
static final String HEADER = "[LWJGL] OpenGL debug message";
|
|
||||||
public final EType type;
|
|
||||||
public final ESeverity severity;
|
|
||||||
public final ESource source;
|
|
||||||
public final String id;
|
|
||||||
public final String message;
|
|
||||||
|
|
||||||
/** This is needed since gl callback will not have the correct class loader set, which causes issues. */
|
|
||||||
static void initLoadClass()
|
|
||||||
{
|
|
||||||
Builder dummy = new Builder();
|
|
||||||
dummy.add(GLMessage.HEADER);
|
|
||||||
dummy.add("ID");
|
|
||||||
dummy.add(":");
|
|
||||||
dummy.add("dummyId");
|
|
||||||
dummy.add("Source");
|
|
||||||
dummy.add(":");
|
|
||||||
dummy.add(ESource.API.name);
|
|
||||||
dummy.add("Type");
|
|
||||||
dummy.add(":");
|
|
||||||
dummy.add(EType.OTHER.name);
|
|
||||||
dummy.add("Severity");
|
|
||||||
dummy.add(":");
|
|
||||||
dummy.add(ESeverity.LOW.name);
|
|
||||||
dummy.add("Message");
|
|
||||||
dummy.add(":");
|
|
||||||
dummy.add("dummyMessage");
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
initLoadClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GLMessage(EType type, ESeverity severity, ESource source, String id, String message)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
this.source = source;
|
|
||||||
this.severity = severity;
|
|
||||||
this.id = id;
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() { return "[level:" + severity + ", type:" + type + ", source:" + source + ", id:" + id + ", msg:{" + message + "}]"; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
|
||||||
// helper enums //
|
|
||||||
//==============//
|
|
||||||
|
|
||||||
public enum EType
|
|
||||||
{
|
|
||||||
ERROR,
|
|
||||||
DEPRECATED_BEHAVIOR,
|
|
||||||
UNDEFINED_BEHAVIOR,
|
|
||||||
PORTABILITY,
|
|
||||||
PERFORMANCE,
|
|
||||||
MARKER,
|
|
||||||
PUSH_GROUP,
|
|
||||||
POP_GROUP,
|
|
||||||
OTHER;
|
|
||||||
|
|
||||||
|
|
||||||
private static final HashMap<String, EType> ENUM_BY_NAME = new HashMap<>();
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for (EType type : EType.values())
|
|
||||||
{
|
|
||||||
ENUM_BY_NAME.put(type.name, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EType() { name = super.toString().toUpperCase(); }
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() { return name; }
|
|
||||||
|
|
||||||
public static EType get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ESource
|
|
||||||
{
|
|
||||||
API,
|
|
||||||
WINDOW_SYSTEM,
|
|
||||||
SHADER_COMPILER,
|
|
||||||
THIRD_PARTY,
|
|
||||||
APPLICATION,
|
|
||||||
OTHER;
|
|
||||||
|
|
||||||
|
|
||||||
private static final HashMap<String, ESource> ENUM_BY_NAME = new HashMap<>();
|
|
||||||
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for (ESource source : ESource.values())
|
|
||||||
{
|
|
||||||
ENUM_BY_NAME.put(source.name, source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ESource() { name = super.toString().toUpperCase(); }
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() { return name; }
|
|
||||||
|
|
||||||
public static ESource get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ESeverity
|
|
||||||
{
|
|
||||||
HIGH,
|
|
||||||
MEDIUM,
|
|
||||||
LOW,
|
|
||||||
NOTIFICATION;
|
|
||||||
|
|
||||||
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
static final HashMap<String, ESeverity> ENUM_BY_NAME = new HashMap<>();
|
|
||||||
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for (ESeverity severity : ESeverity.values())
|
|
||||||
{
|
|
||||||
ENUM_BY_NAME.put(severity.name, severity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ESeverity() { name = super.toString().toUpperCase(); }
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() { return name; }
|
|
||||||
|
|
||||||
public static ESeverity get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
|
||||||
// helper classes //
|
|
||||||
//================//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expected message format: <br>
|
|
||||||
* <code>
|
|
||||||
* [LWJGL] OpenGL debug message <br>
|
|
||||||
* ID: 0x20071 <br>
|
|
||||||
* Source: API <br>
|
|
||||||
* Type: OTHER <br>
|
|
||||||
* Severity: NOTIFICATION <br>
|
|
||||||
* Message: Buffer detailed info: Buffer object 1014084 (bound to ...
|
|
||||||
* </code>
|
|
||||||
*/
|
|
||||||
public static class Builder
|
|
||||||
{
|
|
||||||
/** how many stages are present in the message parser */
|
|
||||||
private static final int FINAL_PARSER_STAGE_INDEX = 15;
|
|
||||||
|
|
||||||
public static final Builder DEFAULT_MESSAGE_BUILDER =
|
|
||||||
new Builder(
|
|
||||||
(type) ->
|
|
||||||
{ // type filter
|
|
||||||
if (type == GLMessage.EType.POP_GROUP)
|
|
||||||
return false;
|
|
||||||
if (type == GLMessage.EType.PUSH_GROUP)
|
|
||||||
return false;
|
|
||||||
if (type == GLMessage.EType.MARKER)
|
|
||||||
return false;
|
|
||||||
// if (type == GLMessage.Type.PERFORMANCE) return false;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
(severity) ->
|
|
||||||
{ // severity filter
|
|
||||||
if (severity == GLMessage.ESeverity.NOTIFICATION)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
private final StringBuilder inProgressMessageBuilder = new StringBuilder();
|
|
||||||
|
|
||||||
private EType type;
|
|
||||||
private ESeverity severity;
|
|
||||||
private ESource source;
|
|
||||||
|
|
||||||
/** if the function returns false the message will be allowed */
|
|
||||||
private final Function<EType, Boolean> typeFilter;
|
|
||||||
/** if the function returns false the message will be allowed */
|
|
||||||
private final Function<ESeverity, Boolean> severityFilter;
|
|
||||||
/** if the function returns false the message will be allowed */
|
|
||||||
private final Function<ESource, Boolean> sourceFilter;
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String message;
|
|
||||||
/** how far into the message parser this builder is */
|
|
||||||
private int parserStage = 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
initLoadClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder() { this(null, null, null); }
|
|
||||||
|
|
||||||
public Builder(
|
|
||||||
Function<EType, Boolean> typeFilter,
|
|
||||||
Function<ESeverity, Boolean> severityFilter,
|
|
||||||
Function<ESource, Boolean> sourceFilter)
|
|
||||||
{
|
|
||||||
this.typeFilter = typeFilter;
|
|
||||||
this.severityFilter = severityFilter;
|
|
||||||
this.sourceFilter = sourceFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the given string to the message builder. <br> <br>
|
|
||||||
*
|
|
||||||
* Will log a warning if the string given wasn't expected
|
|
||||||
* for the next stage of the OpenGL message format.<br> <br>
|
|
||||||
*
|
|
||||||
* @return null if the message isn't complete
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
boolean parseSuccess = runNextParserStage(str);
|
|
||||||
if (parseSuccess && parserStage > FINAL_PARSER_STAGE_INDEX)
|
|
||||||
{
|
|
||||||
this.parserStage = 0;
|
|
||||||
GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
|
|
||||||
if (doesMessagePassFilters(msg))
|
|
||||||
{
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!parseSuccess)
|
|
||||||
{
|
|
||||||
LOGGER.warn("Failed to parse GLMessage line '{}' at stage {}", str, parserStage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the message isn't finished yet
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// TODO implement a method that works for both MC 1.20.2+ and 1.20.1-
|
|
||||||
//if (str.equals(HEADER) && inProgressMessageBuilder.length() != 0)
|
|
||||||
//{
|
|
||||||
// boolean parseSuccess = runNextParserStage(str);
|
|
||||||
// if (parseSuccess && parserStage > FINAL_PARSER_STAGE_INDEX)
|
|
||||||
// {
|
|
||||||
// this.parserStage = 0;
|
|
||||||
// GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
|
|
||||||
// if (doesMessagePassFilters(msg))
|
|
||||||
// {
|
|
||||||
// return msg;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// inProgressMessageBuilder.setLength(0);
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// if (!parseSuccess)
|
|
||||||
// {
|
|
||||||
// LOGGER.warn("Failed to parse GLMessage line '{}' at stage {}", str, parserStage);
|
|
||||||
// inProgressMessageBuilder.setLength(0);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// inProgressMessageBuilder.append(str);
|
|
||||||
// return null;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean doesMessagePassFilters(GLMessage msg)
|
|
||||||
{
|
|
||||||
if (this.sourceFilter != null && !this.sourceFilter.apply(msg.source))
|
|
||||||
return false;
|
|
||||||
else if (this.typeFilter != null && !this.typeFilter.apply(msg.type))
|
|
||||||
return false;
|
|
||||||
else if (this.severityFilter != null && !this.severityFilter.apply(msg.severity))
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return true if the given string was expected next for the OpenGL message format */
|
|
||||||
private boolean runNextParserStage(String str)
|
|
||||||
{
|
|
||||||
switch (this.parserStage)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return checkAndIncStage(str, GLMessage.HEADER);
|
|
||||||
case 1:
|
|
||||||
return checkAndIncStage(str, "ID");
|
|
||||||
case 2:
|
|
||||||
return checkAndIncStage(str, ":");
|
|
||||||
case 3:
|
|
||||||
this.id = str;
|
|
||||||
this.parserStage++;
|
|
||||||
return true;
|
|
||||||
case 4:
|
|
||||||
return checkAndIncStage(str, "Source");
|
|
||||||
case 5:
|
|
||||||
return checkAndIncStage(str, ":");
|
|
||||||
case 6:
|
|
||||||
this.source = ESource.get(str);
|
|
||||||
this.parserStage++;
|
|
||||||
return true;
|
|
||||||
case 7:
|
|
||||||
return checkAndIncStage(str, "Type");
|
|
||||||
case 8:
|
|
||||||
return checkAndIncStage(str, ":");
|
|
||||||
case 9:
|
|
||||||
this.type = EType.get(str);
|
|
||||||
this.parserStage++;
|
|
||||||
return true;
|
|
||||||
case 10:
|
|
||||||
return checkAndIncStage(str, "Severity");
|
|
||||||
case 11:
|
|
||||||
return checkAndIncStage(str, ":");
|
|
||||||
case 12:
|
|
||||||
this.severity = ESeverity.get(str);
|
|
||||||
this.parserStage++;
|
|
||||||
return true;
|
|
||||||
case 13:
|
|
||||||
return checkAndIncStage(str, "Message");
|
|
||||||
case 14:
|
|
||||||
return checkAndIncStage(str, ":");
|
|
||||||
case 15:
|
|
||||||
this.message = str;
|
|
||||||
this.parserStage++;
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true and increments the parserStage
|
|
||||||
* if the given and expected strings are the same.
|
|
||||||
*/
|
|
||||||
private boolean checkAndIncStage(String givenString, String expectedString)
|
|
||||||
{
|
|
||||||
boolean equal = givenString.equals(expectedString);
|
|
||||||
//boolean equal = givenString.contains(expectedString);
|
|
||||||
if (equal)
|
|
||||||
this.parserStage++;
|
|
||||||
return equal;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // builder class
|
|
||||||
|
|
||||||
}
|
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU 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.util.objects.GLMessages;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public enum EGLMessageSeverity
|
||||||
|
{
|
||||||
|
HIGH,
|
||||||
|
MEDIUM,
|
||||||
|
LOW,
|
||||||
|
NOTIFICATION;
|
||||||
|
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
static final HashMap<String, EGLMessageSeverity> ENUM_BY_NAME = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (EGLMessageSeverity severity : EGLMessageSeverity.values())
|
||||||
|
{
|
||||||
|
ENUM_BY_NAME.put(severity.name, severity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLMessageSeverity() { this.name = super.toString().toUpperCase(); }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() { return this.name; }
|
||||||
|
|
||||||
|
public static EGLMessageSeverity get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU 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.util.objects.GLMessages;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public enum EGLMessageSource
|
||||||
|
{
|
||||||
|
API,
|
||||||
|
WINDOW_SYSTEM,
|
||||||
|
SHADER_COMPILER,
|
||||||
|
THIRD_PARTY,
|
||||||
|
APPLICATION,
|
||||||
|
OTHER;
|
||||||
|
|
||||||
|
|
||||||
|
private static final HashMap<String, EGLMessageSource> ENUM_BY_NAME = new HashMap<>();
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (EGLMessageSource source : EGLMessageSource.values())
|
||||||
|
{
|
||||||
|
ENUM_BY_NAME.put(source.name, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLMessageSource() { this.name = super.toString().toUpperCase(); }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() { return this.name; }
|
||||||
|
|
||||||
|
public static EGLMessageSource get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||||
|
|
||||||
|
}
|
||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU 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.util.objects.GLMessages;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public enum EGLMessageType
|
||||||
|
{
|
||||||
|
ERROR,
|
||||||
|
DEPRECATED_BEHAVIOR,
|
||||||
|
UNDEFINED_BEHAVIOR,
|
||||||
|
PORTABILITY,
|
||||||
|
PERFORMANCE,
|
||||||
|
MARKER,
|
||||||
|
PUSH_GROUP,
|
||||||
|
POP_GROUP,
|
||||||
|
OTHER;
|
||||||
|
|
||||||
|
|
||||||
|
private static final HashMap<String, EGLMessageType> ENUM_BY_NAME = new HashMap<>();
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (EGLMessageType type : EGLMessageType.values())
|
||||||
|
{
|
||||||
|
ENUM_BY_NAME.put(type.name, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLMessageType() { this.name = super.toString().toUpperCase(); }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() { return this.name; }
|
||||||
|
|
||||||
|
public static EGLMessageType get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||||
|
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU 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.util.objects.GLMessages;
|
||||||
|
|
||||||
|
public final class GLMessage
|
||||||
|
{
|
||||||
|
static final String HEADER = "[LWJGL] OpenGL debug message";
|
||||||
|
public final EGLMessageType type;
|
||||||
|
public final EGLMessageSeverity severity;
|
||||||
|
public final EGLMessageSource source;
|
||||||
|
public final String id;
|
||||||
|
public final String message;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GLMessage(EGLMessageType type, EGLMessageSeverity severity, EGLMessageSource source, String id, String message)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.source = source;
|
||||||
|
this.severity = severity;
|
||||||
|
this.id = id;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "level: [" + this.severity + "], " +
|
||||||
|
"type: [" + this.type + "], " +
|
||||||
|
"source: [" + this.source + "], " +
|
||||||
|
"id: [" + this.id + "], " +
|
||||||
|
"msg: [" + this.message + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+319
@@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU 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.util.objects.GLMessages;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/** Expected message formats can be found in GLMessageTest. */
|
||||||
|
public class GLMessageBuilder
|
||||||
|
{
|
||||||
|
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||||
|
|
||||||
|
/** how many stages are present in the message parser */
|
||||||
|
private static final int FINAL_LEGACY_PARSER_STAGE_INDEX = 15;
|
||||||
|
private static final int FINAL_NEW_PARSER_STAGE_INDEX = 5;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private EGLMessageType type;
|
||||||
|
private EGLMessageSeverity severity;
|
||||||
|
private EGLMessageSource source;
|
||||||
|
|
||||||
|
/** if the function returns false the message will be allowed */
|
||||||
|
private final Function<EGLMessageType, Boolean> typeFilter;
|
||||||
|
/** if the function returns false the message will be allowed */
|
||||||
|
private final Function<EGLMessageSeverity, Boolean> severityFilter;
|
||||||
|
/** if the function returns false the message will be allowed */
|
||||||
|
private final Function<EGLMessageSource, Boolean> sourceFilter;
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String message;
|
||||||
|
/** how far into the message parser this builder is */
|
||||||
|
private int parserStage = 0;
|
||||||
|
|
||||||
|
private boolean legacyMessage = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
|
||||||
|
public GLMessageBuilder() { this(null, null, null); }
|
||||||
|
|
||||||
|
public GLMessageBuilder(
|
||||||
|
Function<EGLMessageType, Boolean> typeFilter,
|
||||||
|
Function<EGLMessageSeverity, Boolean> severityFilter,
|
||||||
|
Function<EGLMessageSource, Boolean> sourceFilter)
|
||||||
|
{
|
||||||
|
this.typeFilter = typeFilter;
|
||||||
|
this.severityFilter = severityFilter;
|
||||||
|
this.sourceFilter = sourceFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// message parsing //
|
||||||
|
//=================//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given string to the message builder. <br> <br>
|
||||||
|
*
|
||||||
|
* Will log a warning if the string given wasn't expected
|
||||||
|
* for the next stage of the OpenGL message format.<br> <br>
|
||||||
|
*
|
||||||
|
* @return null if the message isn't complete
|
||||||
|
*/
|
||||||
|
public GLMessage add(String str)
|
||||||
|
{
|
||||||
|
str = str.trim();
|
||||||
|
if (str.isEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean messageFinished = false;
|
||||||
|
boolean parseSuccess = this.runNextParserStage(str);
|
||||||
|
|
||||||
|
|
||||||
|
if (this.legacyMessage
|
||||||
|
&& this.parserStage > FINAL_LEGACY_PARSER_STAGE_INDEX)
|
||||||
|
{
|
||||||
|
messageFinished = true;
|
||||||
|
}
|
||||||
|
else if (!this.legacyMessage
|
||||||
|
&& this.parserStage > FINAL_NEW_PARSER_STAGE_INDEX)
|
||||||
|
{
|
||||||
|
messageFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (parseSuccess && messageFinished)
|
||||||
|
{
|
||||||
|
this.parserStage = 0;
|
||||||
|
GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
|
||||||
|
if (this.doesMessagePassFilters(msg))
|
||||||
|
{
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!parseSuccess && messageFinished)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Failed to parse GLMessage line [" + str + "] at stage [" + this.parserStage + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
// the message isn't finished yet
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doesMessagePassFilters(GLMessage msg)
|
||||||
|
{
|
||||||
|
if (this.sourceFilter != null && !this.sourceFilter.apply(msg.source))
|
||||||
|
return false;
|
||||||
|
else if (this.typeFilter != null && !this.typeFilter.apply(msg.type))
|
||||||
|
return false;
|
||||||
|
else if (this.severityFilter != null && !this.severityFilter.apply(msg.severity))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return true if the given string was expected next for the OpenGL message format */
|
||||||
|
private boolean runNextParserStage(String str)
|
||||||
|
{
|
||||||
|
if (this.parserStage == 0)
|
||||||
|
{
|
||||||
|
return this.checkExactAndIncStage(str, GLMessage.HEADER);
|
||||||
|
}
|
||||||
|
else if (this.parserStage == 1)
|
||||||
|
{
|
||||||
|
// legacy message only contains "ID" (not the colon)
|
||||||
|
this.legacyMessage = !str.contains("ID: ");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.legacyMessage)
|
||||||
|
{
|
||||||
|
return this.runNextLegacyParserStage(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.runNextNewParserStage(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** MC 1.20.2 and older */
|
||||||
|
private boolean runNextLegacyParserStage(String str)
|
||||||
|
{
|
||||||
|
switch (this.parserStage)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
throw new IllegalStateException("Parser should be past stage ["+this.parserStage+"], next stage is [1].");
|
||||||
|
case 1:
|
||||||
|
return this.checkExactAndIncStage(str, "ID");
|
||||||
|
case 2:
|
||||||
|
return this.checkExactAndIncStage(str, ":");
|
||||||
|
case 3:
|
||||||
|
this.id = str;
|
||||||
|
this.parserStage++;
|
||||||
|
return true;
|
||||||
|
case 4:
|
||||||
|
return this.checkExactAndIncStage(str, "Source");
|
||||||
|
case 5:
|
||||||
|
return this.checkExactAndIncStage(str, ":");
|
||||||
|
case 6:
|
||||||
|
this.source = EGLMessageSource.get(str);
|
||||||
|
this.parserStage++;
|
||||||
|
return true;
|
||||||
|
case 7:
|
||||||
|
return this.checkExactAndIncStage(str, "Type");
|
||||||
|
case 8:
|
||||||
|
return this.checkExactAndIncStage(str, ":");
|
||||||
|
case 9:
|
||||||
|
this.type = EGLMessageType.get(str);
|
||||||
|
this.parserStage++;
|
||||||
|
return true;
|
||||||
|
case 10:
|
||||||
|
return this.checkExactAndIncStage(str, "Severity");
|
||||||
|
case 11:
|
||||||
|
return this.checkExactAndIncStage(str, ":");
|
||||||
|
case 12:
|
||||||
|
this.severity = EGLMessageSeverity.get(str);
|
||||||
|
this.parserStage++;
|
||||||
|
return true;
|
||||||
|
case 13:
|
||||||
|
return this.checkExactAndIncStage(str, "Message");
|
||||||
|
case 14:
|
||||||
|
return this.checkExactAndIncStage(str, ":");
|
||||||
|
case 15:
|
||||||
|
this.message = str;
|
||||||
|
this.parserStage++;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** after MC 1.20.2 */
|
||||||
|
private boolean runNextNewParserStage(String str)
|
||||||
|
{
|
||||||
|
switch (this.parserStage)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
throw new IllegalStateException("Parser should be past stage [" + this.parserStage + "], next stage is [1].");
|
||||||
|
case 1:
|
||||||
|
String idPrefix = "ID: ";
|
||||||
|
return this.checkPrefixAndRun(str, idPrefix,
|
||||||
|
(line) ->
|
||||||
|
{
|
||||||
|
this.id = trySubstring(str, idPrefix.length());
|
||||||
|
this.parserStage++;
|
||||||
|
});
|
||||||
|
case 2:
|
||||||
|
String sourcePrefix = "Source: ";
|
||||||
|
return this.checkPrefixAndRun(str, sourcePrefix,
|
||||||
|
(line) ->
|
||||||
|
{
|
||||||
|
String sourceString = trySubstring(str, sourcePrefix.length());
|
||||||
|
this.source = EGLMessageSource.get(sourceString);
|
||||||
|
this.parserStage++;
|
||||||
|
});
|
||||||
|
case 3:
|
||||||
|
String typePrefix = "Type: ";
|
||||||
|
return this.checkPrefixAndRun(str, typePrefix,
|
||||||
|
(line) ->
|
||||||
|
{
|
||||||
|
String sourceString = trySubstring(str, typePrefix.length());
|
||||||
|
this.type = EGLMessageType.get(sourceString);
|
||||||
|
this.parserStage++;
|
||||||
|
});
|
||||||
|
case 4:
|
||||||
|
String severityPrefix = "Severity: ";
|
||||||
|
return this.checkPrefixAndRun(str, severityPrefix,
|
||||||
|
(line) ->
|
||||||
|
{
|
||||||
|
String sourceString = trySubstring(str, severityPrefix.length());
|
||||||
|
this.severity = EGLMessageSeverity.get(sourceString);
|
||||||
|
this.parserStage++;
|
||||||
|
});
|
||||||
|
case 5:
|
||||||
|
String messagePrefix = "Message: ";
|
||||||
|
return this.checkPrefixAndRun(str, messagePrefix,
|
||||||
|
(line) ->
|
||||||
|
{
|
||||||
|
this.message = trySubstring(str, messagePrefix.length());
|
||||||
|
this.parserStage++;
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true and increments the parserStage
|
||||||
|
* if the message and expected strings are the same.
|
||||||
|
*/
|
||||||
|
private boolean checkExactAndIncStage(String message, String expectedString)
|
||||||
|
{
|
||||||
|
boolean equal = message.equals(expectedString);
|
||||||
|
if (equal)
|
||||||
|
{
|
||||||
|
this.parserStage++;
|
||||||
|
}
|
||||||
|
return equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true and increments the parserStage
|
||||||
|
* if the message starts with the given prefix.
|
||||||
|
*/
|
||||||
|
private boolean checkPrefixAndRun(String message, String expectedPrefix, Consumer<String> successConsumer)
|
||||||
|
{
|
||||||
|
boolean equal = message.startsWith(expectedPrefix);
|
||||||
|
if (equal)
|
||||||
|
{
|
||||||
|
successConsumer.accept(message);
|
||||||
|
}
|
||||||
|
return equal;
|
||||||
|
}
|
||||||
|
/** returns "" if the string isn't long enough */
|
||||||
|
private static String trySubstring(String string, int beginIndex)
|
||||||
|
{
|
||||||
|
if (beginIndex > string.length())
|
||||||
|
{
|
||||||
|
// prevent index-out-of-bounds errors
|
||||||
|
// if the message isn't what we expected
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.substring(beginIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+17
-11
@@ -17,7 +17,7 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.seibel.distanthorizons.core.util.objects;
|
package com.seibel.distanthorizons.core.util.objects.GLMessages;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -27,12 +27,12 @@ import java.util.function.Consumer;
|
|||||||
public final class GLMessageOutputStream extends OutputStream
|
public final class GLMessageOutputStream extends OutputStream
|
||||||
{
|
{
|
||||||
final Consumer<GLMessage> func;
|
final Consumer<GLMessage> func;
|
||||||
final GLMessage.Builder builder;
|
final GLMessageBuilder builder;
|
||||||
|
|
||||||
|
|
||||||
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
public GLMessageOutputStream(Consumer<GLMessage> func, GLMessage.Builder builder)
|
public GLMessageOutputStream(Consumer<GLMessage> func, GLMessageBuilder builder)
|
||||||
{
|
{
|
||||||
this.func = func;
|
this.func = func;
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
@@ -41,24 +41,30 @@ public final class GLMessageOutputStream extends OutputStream
|
|||||||
@Override
|
@Override
|
||||||
public void write(int b)
|
public void write(int b)
|
||||||
{
|
{
|
||||||
buffer.write(b);
|
this.buffer.write(b);
|
||||||
if (b == '\n') flush();
|
if (b == '\n')
|
||||||
|
{
|
||||||
|
this.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush()
|
public void flush()
|
||||||
{
|
{
|
||||||
String str = buffer.toString();
|
String str = this.buffer.toString();
|
||||||
GLMessage msg = builder.add(str);
|
GLMessage msg = this.builder.add(str);
|
||||||
if (msg != null) func.accept(msg);
|
if (msg != null)
|
||||||
buffer.reset();
|
{
|
||||||
|
this.func.accept(msg);
|
||||||
|
}
|
||||||
|
this.buffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException
|
public void close() throws IOException
|
||||||
{
|
{
|
||||||
flush();
|
this.flush();
|
||||||
buffer.close();
|
this.buffer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+4
-2
@@ -78,9 +78,11 @@ public class RateLimitedThreadPoolExecutor extends ThreadPoolExecutor
|
|||||||
long runTime = System.nanoTime() - this.runStartTime.get();
|
long runTime = System.nanoTime() - this.runStartTime.get();
|
||||||
Thread.sleep(TimeUnit.NANOSECONDS.toMillis((long) (runTime / this.runTimeRatioConfig.get() - runTime)));
|
Thread.sleep(TimeUnit.NANOSECONDS.toMillis((long) (runTime / this.runTimeRatioConfig.get() - runTime)));
|
||||||
}
|
}
|
||||||
catch (InterruptedException e)
|
catch (InterruptedException ignore)
|
||||||
{
|
{
|
||||||
throw new RuntimeException(e);
|
// if this thread is interrupted that means the
|
||||||
|
// thread pool is being shut down,
|
||||||
|
// we don't need to log that.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-2
@@ -89,7 +89,14 @@ public class ThreadPoolUtil
|
|||||||
|
|
||||||
public static void setupThreadPools()
|
public static void setupThreadPools()
|
||||||
{
|
{
|
||||||
// thread pools
|
//==================//
|
||||||
|
// main thread pool //
|
||||||
|
//==================//
|
||||||
|
|
||||||
|
if (taskPicker != null)
|
||||||
|
{
|
||||||
|
taskPicker.shutdown();
|
||||||
|
}
|
||||||
taskPicker = new PriorityTaskPicker();
|
taskPicker = new PriorityTaskPicker();
|
||||||
|
|
||||||
networkCompressionThreadPool = taskPicker.createExecutor();
|
networkCompressionThreadPool = taskPicker.createExecutor();
|
||||||
@@ -98,8 +105,22 @@ public class ThreadPoolUtil
|
|||||||
updatePropagatorThreadPool = taskPicker.createExecutor();
|
updatePropagatorThreadPool = taskPicker.createExecutor();
|
||||||
worldGenThreadPool = taskPicker.createExecutor();
|
worldGenThreadPool = taskPicker.createExecutor();
|
||||||
|
|
||||||
// single thread pools
|
|
||||||
|
|
||||||
|
//=========================//
|
||||||
|
// standalone thread pools //
|
||||||
|
//=========================//
|
||||||
|
|
||||||
|
if (beaconCullingThreadPool != null)
|
||||||
|
{
|
||||||
|
beaconCullingThreadPool.shutdown();
|
||||||
|
}
|
||||||
beaconCullingThreadPool = ThreadUtil.makeSingleThreadPool(BEACON_CULLING_THREAD_NAME);
|
beaconCullingThreadPool = ThreadUtil.makeSingleThreadPool(BEACON_CULLING_THREAD_NAME);
|
||||||
|
|
||||||
|
if (fullDataMigrationThreadPool != null)
|
||||||
|
{
|
||||||
|
fullDataMigrationThreadPool.shutdown();
|
||||||
|
}
|
||||||
fullDataMigrationThreadPool = ThreadUtil.makeSingleThreadPool(FULL_DATA_MIGRATION_THREAD_NAME);
|
fullDataMigrationThreadPool = ThreadUtil.makeSingleThreadPool(FULL_DATA_MIGRATION_THREAD_NAME);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
public final ClientOnlySaveStructure saveStructure;
|
public final ClientOnlySaveStructure saveStructure;
|
||||||
public final ClientNetworkState networkState = new ClientNetworkState();
|
public final ClientNetworkState networkState = new ClientNetworkState();
|
||||||
|
|
||||||
public ExecutorService dhTickerThread = ThreadUtil.makeSingleThreadPool("Client World Ticker Thread");
|
public final ExecutorService dhTickerThread = ThreadUtil.makeSingleThreadPool("Client World Ticker Thread");
|
||||||
public EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick);
|
public final EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -128,6 +128,8 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
{
|
{
|
||||||
this.networkState.close();
|
this.networkState.close();
|
||||||
|
|
||||||
|
this.dhTickerThread.shutdownNow();
|
||||||
|
|
||||||
|
|
||||||
for (DhClientLevel dhClientLevel : this.levels.values())
|
for (DhClientLevel dhClientLevel : this.levels.values())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public class DhServerWorld extends AbstractDhServerWorld<DhServerLevel>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// level handling //
|
// level handling //
|
||||||
//================//
|
//================//
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ import com.seibel.distanthorizons.core.level.IDhLevel;
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public interface IDhWorld
|
// TODO why is this exist alongside AbstractDhWorld?
|
||||||
|
public interface IDhWorld extends Closeable
|
||||||
{
|
{
|
||||||
|
|
||||||
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
|
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
|
||||||
|
|||||||
+5
@@ -49,6 +49,11 @@ public interface IBlockStateWrapper extends IDhApiBlockStateWrapper
|
|||||||
boolean isBeaconBlock();
|
boolean isBeaconBlock();
|
||||||
/** IE a glass block that can affect the beacon beam color */
|
/** IE a glass block that can affect the beacon beam color */
|
||||||
boolean isBeaconTintBlock();
|
boolean isBeaconTintBlock();
|
||||||
|
/**
|
||||||
|
* Returns true for any blocks that allow beacon beams to go through.
|
||||||
|
* IE: glass, stairs, bedrock, chests, end portal frames, carpet, cake
|
||||||
|
*/
|
||||||
|
boolean allowsBeaconBeamPassage();
|
||||||
/**
|
/**
|
||||||
* The blocks used by a beacon's base
|
* The blocks used by a beacon's base
|
||||||
* IE Iron, diamond, gold, etc.
|
* IE Iron, diamond, gold, etc.
|
||||||
|
|||||||
+2
-1
@@ -381,8 +381,9 @@ public interface IChunkWrapper extends IBindable
|
|||||||
for (int y = beaconRelPos.getY() +1; y <= maxY; y++)
|
for (int y = beaconRelPos.getY() +1; y <= maxY; y++)
|
||||||
{
|
{
|
||||||
IBlockStateWrapper block = centerChunk.getBlockState(beaconRelPos.getX(), y, beaconRelPos.getZ());
|
IBlockStateWrapper block = centerChunk.getBlockState(beaconRelPos.getX(), y, beaconRelPos.getZ());
|
||||||
if (!block.isAir() && block.getOpacity() == LodUtil.BLOCK_FULLY_OPAQUE)
|
if (!block.allowsBeaconBeamPassage())
|
||||||
{
|
{
|
||||||
|
// beam is blocked by this block
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -60,6 +60,9 @@ public interface IMinecraftRenderWrapper extends IBindable
|
|||||||
int getScreenWidth();
|
int getScreenWidth();
|
||||||
int getScreenHeight();
|
int getScreenHeight();
|
||||||
|
|
||||||
|
boolean mcRendersToFrameBuffer();
|
||||||
|
boolean runningLegacyOpenGL();
|
||||||
|
|
||||||
/** @return -1 if no valid framebuffer is available yet */
|
/** @return -1 if no valid framebuffer is available yet */
|
||||||
int getTargetFrameBuffer(); // Note: Iris is now hooking onto this for DH + Iris compat, try not to change (unless we wanna deal with some annoyances)
|
int getTargetFrameBuffer(); // Note: Iris is now hooking onto this for DH + Iris compat, try not to change (unless we wanna deal with some annoyances)
|
||||||
// Iris commit: https://github.com/IrisShaders/Iris/commit/a76a240527e93780bbcba57c09bef377419d47a7#diff-7b9ded0c79bbcdb130010373387756a28ee8d3640d522c0a5b7acd0abbfc20aeR16
|
// Iris commit: https://github.com/IrisShaders/Iris/commit/a76a240527e93780bbcba57c09bef377419d47a7#diff-7b9ded0c79bbcdb130010373387756a28ee8d3640d522c0a5b7acd0abbfc20aeR16
|
||||||
|
|||||||
@@ -477,7 +477,11 @@
|
|||||||
"distanthorizons.config.client.advanced.debugging.openGl.overrideVanillaGLLogger":
|
"distanthorizons.config.client.advanced.debugging.openGl.overrideVanillaGLLogger":
|
||||||
"Override Vanilla GL Logger",
|
"Override Vanilla GL Logger",
|
||||||
"distanthorizons.config.client.advanced.debugging.openGl.overrideVanillaGLLogger.@tooltip":
|
"distanthorizons.config.client.advanced.debugging.openGl.overrideVanillaGLLogger.@tooltip":
|
||||||
"Defines how OpenGL errors are handled. \n Requires rebooting Minecraft to apply. \nMay incorrectly catch OpenGL errors thrown by other mods.",
|
"Defines how OpenGL errors are handled. \nRequires rebooting Minecraft to change. \nWill catch OpenGL errors thrown by other mods.",
|
||||||
|
"distanthorizons.config.client.advanced.debugging.openGl.onlyLogGlErrorsOnce":
|
||||||
|
"Only Log GL Errors Once",
|
||||||
|
"distanthorizons.config.client.advanced.debugging.openGl.onlyLogGlErrorsOnce.@tooltip":
|
||||||
|
"If true each Open GL error will only be logged once. \nTEnabling this may cause some error logs to be missed. \nDoes nothing if overrideVanillaGLLogger is set to false. \n\nGenerally this can be kept as 'true' to prevent log spam. \nHowever, Please set this to 'false' if a developer needs your log to debug a GL issue. \n",
|
||||||
"distanthorizons.config.client.advanced.debugging.openGl.glErrorHandlingMode":
|
"distanthorizons.config.client.advanced.debugging.openGl.glErrorHandlingMode":
|
||||||
"OpenGL Error Handling Mode",
|
"OpenGL Error Handling Mode",
|
||||||
"distanthorizons.config.client.advanced.debugging.openGl.glErrorHandlingMode.@tooltip":
|
"distanthorizons.config.client.advanced.debugging.openGl.glErrorHandlingMode.@tooltip":
|
||||||
|
|||||||
@@ -8,17 +8,26 @@ uniform sampler2D gDhColorTexture;
|
|||||||
uniform sampler2D gDhDepthTexture;
|
uniform sampler2D gDhDepthTexture;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LOD application shader
|
||||||
|
*
|
||||||
|
* This merges the rendered LODs into Minecraft's texture/FBO
|
||||||
|
*/
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
fragColor = vec4(0.0);
|
fragColor = vec4(0.0);
|
||||||
|
|
||||||
float fragmentDepth = texture(gDhDepthTexture, TexCoord).r;
|
|
||||||
|
|
||||||
// a fragment depth of "1" means the fragment wasn't drawn to,
|
// a fragment depth of "1" means the fragment wasn't drawn to,
|
||||||
// only update fragments that were drawn to
|
// only update fragments that were drawn to
|
||||||
if (fragmentDepth != 1)
|
float fragmentDepth = texture(gDhDepthTexture, TexCoord).r;
|
||||||
|
if (fragmentDepth != 1)
|
||||||
{
|
{
|
||||||
fragColor = texture(gDhColorTexture, TexCoord);
|
fragColor = texture(gDhColorTexture, TexCoord);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// use the original MC texture if no LODs were drawn to this fragment
|
||||||
|
discard;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,16 +8,19 @@ uniform sampler2D uColorTexture;
|
|||||||
uniform sampler2D uDepthTexture;
|
uniform sampler2D uDepthTexture;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fog application shader
|
||||||
|
*
|
||||||
|
* This merges the rendered fog onto DH's rendered LODs
|
||||||
|
*/
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
fragColor = vec4(1.0);
|
fragColor = vec4(0.0);
|
||||||
|
|
||||||
float fragmentDepth = textureLod(uDepthTexture, TexCoord, 0).r;
|
|
||||||
|
|
||||||
// a fragment depth of "1" means the fragment wasn't drawn to,
|
// a fragment depth of "1" means the fragment wasn't drawn to,
|
||||||
// only update fragments that were drawn to
|
// only update fragments that were drawn to
|
||||||
if (fragmentDepth != 1)
|
float fragmentDepth = textureLod(uDepthTexture, TexCoord, 0).r;
|
||||||
|
if (fragmentDepth != 1)
|
||||||
{
|
{
|
||||||
fragColor = texture(uColorTexture, TexCoord);
|
fragColor = texture(uColorTexture, TexCoord);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
import com.seibel.distanthorizons.core.sql.DatabaseUpdater;
|
import com.seibel.distanthorizons.core.sql.DatabaseUpdater;
|
||||||
import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
|
import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
|
||||||
|
import com.seibel.distanthorizons.core.sql.repo.phantoms.AutoClosableTrackingWrapper;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
@@ -218,6 +219,12 @@ public class DhRepoSqliteTest
|
|||||||
@Test
|
@Test
|
||||||
public void testRepoLeakDetection()
|
public void testRepoLeakDetection()
|
||||||
{
|
{
|
||||||
|
if (!AutoClosableTrackingWrapper.TRACK_WRAPPERS)
|
||||||
|
{
|
||||||
|
System.out.println("Skipping repo leak detection unit test. Leak tracking is disabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TestPrimaryKeyRepo primaryKeyRepo = null;
|
TestPrimaryKeyRepo primaryKeyRepo = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -298,7 +305,8 @@ public class DhRepoSqliteTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size()); // TODO fails when built for release due to tracking being disabled
|
// TODO fails when built for release due to tracking being disabled
|
||||||
|
Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
||||||
primaryKeyRepo.openClosables.clear();
|
primaryKeyRepo.openClosables.clear();
|
||||||
|
|
||||||
|
|
||||||
@@ -318,7 +326,7 @@ public class DhRepoSqliteTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException e)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
package tests;
|
package tests;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.util.objects.GLMessage;
|
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -28,66 +28,88 @@ import java.util.ArrayList;
|
|||||||
public class GLMessageTest
|
public class GLMessageTest
|
||||||
{
|
{
|
||||||
public static final String MESSAGE_ID = "0x20071";
|
public static final String MESSAGE_ID = "0x20071";
|
||||||
public static final GLMessage.ESource MESSAGE_SOURCE = GLMessage.ESource.API;
|
public static final EGLMessageSource MESSAGE_SOURCE = EGLMessageSource.API;
|
||||||
public static final GLMessage.EType MESSAGE_TYPE = GLMessage.EType.OTHER;
|
public static final EGLMessageType MESSAGE_TYPE = EGLMessageType.OTHER;
|
||||||
public static final GLMessage.ESeverity MESSAGE_SEVERITY = GLMessage.ESeverity.NOTIFICATION;
|
public static final EGLMessageSeverity MESSAGE_SEVERITY = EGLMessageSeverity.NOTIFICATION;
|
||||||
public static final String MESSAGE = "Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations.";
|
public static final String MESSAGE = "Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations.";
|
||||||
|
|
||||||
|
|
||||||
/** This is how debug messages were sent prior to Minecraft 1.20.2 */
|
/** This is how debug messages were sent prior to Minecraft 1.20.2 */
|
||||||
private static final String[] PRE_1_20_2_MESSAGE_ARRAY =
|
private static final String[] OLD_MESSAGE_ARRAY =
|
||||||
{
|
{
|
||||||
"[LWJGL] OpenGL debug message"
|
"[LWJGL] OpenGL debug message"
|
||||||
,"ID", ":", "0x20071"
|
,"ID", ":", MESSAGE_ID
|
||||||
,"Source", ":", "API"
|
,"Source", ":", MESSAGE_SOURCE.name
|
||||||
,"Type", ":", "OTHER"
|
,"Type", ":", MESSAGE_TYPE.name
|
||||||
,"Severity", ":", "NOTIFICATION"
|
,"Severity", ":", MESSAGE_SEVERITY.name
|
||||||
,"Message", ":", "Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations."
|
,"Message", ":", MESSAGE
|
||||||
|
|
||||||
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
|
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
|
||||||
//,"[LWJGL] OpenGL debug message"
|
//,"[LWJGL] OpenGL debug message"
|
||||||
};
|
};
|
||||||
|
|
||||||
/** This is how debug messages were sent after (and including) Minecraft 1.20.2 */
|
/** This is how debug messages were sent after (and including) Minecraft 1.20.2 */
|
||||||
private static final String[] POST_1_20_2_MESSAGE_ARRAY =
|
private static final String[] NEW_MESSAGE_ARRAY =
|
||||||
{
|
{
|
||||||
"[LWJGL] OpenGL debug message"
|
"[LWJGL] OpenGL debug message"
|
||||||
,"ID: 0x20071"
|
,"ID: " + MESSAGE_ID
|
||||||
,"Source: API"
|
,"Source: " + MESSAGE_SOURCE.name
|
||||||
,"Type: OTHER"
|
,"Type: " + MESSAGE_TYPE.name
|
||||||
,"Severity: NOTIFICATION"
|
,"Severity: " + MESSAGE_SEVERITY.name
|
||||||
,"Message: Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations."
|
,"Message: " + MESSAGE
|
||||||
|
|
||||||
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
|
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
|
||||||
//,"[LWJGL] OpenGL debug message"
|
//,"[LWJGL] OpenGL debug message"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public final GLMessageBuilder messageBuilder = new GLMessageBuilder(null, null, null);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======//
|
||||||
|
// tests //
|
||||||
|
//=======//
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preMc1_20_2()
|
public void preMc1_20_2()
|
||||||
{
|
{
|
||||||
ArrayList<GLMessage> messageList = new ArrayList<>();
|
ArrayList<GLMessage> messageList = new ArrayList<>();
|
||||||
for (String str : PRE_1_20_2_MESSAGE_ARRAY)
|
for (String str : OLD_MESSAGE_ARRAY)
|
||||||
{
|
{
|
||||||
GLMessage message = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER.add(str);
|
GLMessage message = this.messageBuilder.add(str);
|
||||||
if (message != null)
|
if (message != null)
|
||||||
{
|
{
|
||||||
messageList.add(message);
|
messageList.add(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
|
Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
|
||||||
//testMessage(messageList.get(0));
|
messageMatchesExpected(messageList.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mc1_20_2()
|
public void mc1_20_2()
|
||||||
{
|
{
|
||||||
// TODO
|
ArrayList<GLMessage> messageList = new ArrayList<>();
|
||||||
|
for (String str : NEW_MESSAGE_ARRAY)
|
||||||
|
{
|
||||||
|
GLMessage message = this.messageBuilder.add(str);
|
||||||
|
if (message != null)
|
||||||
|
{
|
||||||
|
messageList.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
|
||||||
|
messageMatchesExpected(messageList.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
private static void messageMatchesExpected(GLMessage testMessage)
|
private static void messageMatchesExpected(GLMessage testMessage)
|
||||||
{
|
{
|
||||||
Assert.assertEquals(MESSAGE_ID, testMessage.id);
|
Assert.assertEquals(MESSAGE_ID, testMessage.id);
|
||||||
@@ -97,4 +119,6 @@ public class GLMessageTest
|
|||||||
Assert.assertEquals(MESSAGE, testMessage.message);
|
Assert.assertEquals(MESSAGE, testMessage.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user