Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core
This commit is contained in:
@@ -20,8 +20,5 @@ https://github.com/lz4/lz4-java
|
||||
NightConfig for Json & Toml (config handling)\
|
||||
https://github.com/TheElectronWill/night-config
|
||||
|
||||
SVG Salamander for SVG's\
|
||||
SVG Salamander for SVG support (not being used atm)\
|
||||
https://github.com/blackears/svgSalamander
|
||||
|
||||
FlatLaf for theming (for development testing, may remove later)\
|
||||
https://www.formdev.com/flatlaf/
|
||||
|
||||
@@ -77,3 +77,13 @@ task addSourcesToCompiledJar(type: ShadowJar) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options {
|
||||
// Don't log warnings.
|
||||
// There are a lot of warnings related to missing @param and @return javadocs
|
||||
// that aren't necessary and would clutter up said javadocs.
|
||||
// For more info see: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html
|
||||
addStringOption('Xdoclint:all,-missing', '-quiet')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,18 +20,43 @@ import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverri
|
||||
* For example: you can access singletons which handle the config or event binding. <br><br>
|
||||
*
|
||||
* <strong>Q:</strong> Why should I use this class instead of just getting the API singleton I need? <br>
|
||||
*
|
||||
* <strong>A:</strong> This way there is a lower chance of your code breaking if we change something on our end.
|
||||
* For example, if we realized there is a much better way of handling dependency injection we would keep the
|
||||
* interface the same so your code doesn't have to change. Whereas if you were directly referencing
|
||||
* the concrete object we replaced, there would be issues.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2023-6-29
|
||||
* @version 2023-8-26
|
||||
* @since API 1.0.0
|
||||
*/
|
||||
public class DhApi
|
||||
{
|
||||
/**
|
||||
* If you can see this Java Doc, this can be ignored. <br>
|
||||
* This is just to you know that Javadocs are available and that you should use the API jar
|
||||
* instead of the full mod jar. <br><br>
|
||||
*
|
||||
* Note: Don't use this string in your code. It may change and is only for reference.
|
||||
*/
|
||||
public static String READ_ME =
|
||||
"If you don't see Javadocs something is wrong. \n" +
|
||||
"If you are only using the full DH Mod in your build script, you won't have access to our javadocs and could potentially call into unsafe code. \n" +
|
||||
"\n" +
|
||||
"Please use the API jar in your build script as a compile time dependency " +
|
||||
"and the full DH jar as a runtime dependency. \n" +
|
||||
"\n" +
|
||||
"Please refer to the example API project or the DH Developer Wiki for additional information " +
|
||||
"and suggested setup. \n" + // DH Dev note: no links were included to prevent link rot.
|
||||
"";
|
||||
public static String readMe() { return READ_ME; }
|
||||
/**
|
||||
* This is just a humorous way to reference the {@link DhApi#READ_ME} constant string and hopefully peak a few people's attention
|
||||
* vs the relatively boring "readMe".
|
||||
*/
|
||||
public static String heyYou_YoureFinallyAwake() { return READ_ME; }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <strong>WARNING:</strong>
|
||||
* All objects in this class will be null until after DH initializes for the first time. <br><br>
|
||||
@@ -73,6 +98,7 @@ public class DhApi
|
||||
}
|
||||
|
||||
|
||||
|
||||
// always available //
|
||||
|
||||
/**
|
||||
|
||||
+15
-9
@@ -1,5 +1,7 @@
|
||||
package com.seibel.distanthorizons.api.interfaces.config;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An interface for Distant Horizon's Config.
|
||||
*
|
||||
@@ -16,17 +18,17 @@ public interface IDhApiConfigValue<T>
|
||||
* Returns the True value if either the config cannot be overridden by
|
||||
* the API or if it hasn't been set by the API.
|
||||
*/
|
||||
public T getValue();
|
||||
T getValue();
|
||||
/**
|
||||
* Returns the value held by this config. <br>
|
||||
* This is the value stored in the config file.
|
||||
*/
|
||||
public T getTrueValue();
|
||||
/**
|
||||
T getTrueValue();
|
||||
/*
|
||||
* Returns the value of the config if it was set by the API.
|
||||
* Returns null if the config wasn't set by the API.
|
||||
*/
|
||||
public T getApiValue();
|
||||
//T getApiValue(); // not currently implemented
|
||||
|
||||
/**
|
||||
* Sets the config's value. <br>
|
||||
@@ -36,16 +38,20 @@ public interface IDhApiConfigValue<T>
|
||||
*
|
||||
* @return true if the value was set, false otherwise.
|
||||
*/
|
||||
public boolean setValue(T newValue);
|
||||
boolean setValue(T newValue);
|
||||
|
||||
/** Returns true if this config can be set via the API, false otherwise. */
|
||||
public boolean getCanBeOverrodeByApi();
|
||||
boolean getCanBeOverrodeByApi();
|
||||
|
||||
/** Returns the default value for this config. */
|
||||
public T getDefaultValue();
|
||||
T getDefaultValue();
|
||||
/** Returns the max value for this config, null if there is no max. */
|
||||
public T getMaxValue();
|
||||
T getMaxValue();
|
||||
/** Returns the min value for this config, null if there is no min. */
|
||||
public T getMinValue();
|
||||
T getMinValue();
|
||||
|
||||
/** Adds a {@link Consumer} that will be called whenever the config changes to a new value. */
|
||||
void addChangeListener(Consumer<T> onValueChangeFunc);
|
||||
//void removeListener(Consumer<T> onValueChangeFunc); // not currently implemented
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -35,6 +35,8 @@ public interface IDhApiEventInjector extends IDependencyInjector<IDhApiEvent>
|
||||
/**
|
||||
* Unlinks the given event handler, preventing the handler from being called in the future.
|
||||
*
|
||||
* @param dependencyInterface the base interface for the {@link IDhApiEvent}
|
||||
* @param dependencyClassToRemove the concrete {@link IDhApiEvent} class to remove
|
||||
* @return true if the handler was unbound, false if the handler wasn't bound.
|
||||
* @throws IllegalArgumentException if the implementation object doesn't implement the interface
|
||||
*/
|
||||
@@ -48,6 +50,7 @@ public interface IDhApiEventInjector extends IDependencyInjector<IDhApiEvent>
|
||||
* @param abstractEvent event type
|
||||
* @param eventParameterObject event parameter
|
||||
* @param <T> the parameter type taken by the event handlers.
|
||||
* @param <U> the {@link IDhApiEvent}'s class
|
||||
* @return if any of bound event handlers returned that this event should be canceled.
|
||||
*/
|
||||
<T, U extends IDhApiEvent<T>> boolean fireAllEvents(Class<U> abstractEvent, T eventParameterObject);
|
||||
|
||||
+3
-1
@@ -13,8 +13,10 @@ import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverri
|
||||
public interface IDhApiOverrideable extends IBindable
|
||||
{
|
||||
/**
|
||||
* Higher (larger numerical) priorities override lower (smaller numerical) priorities . <br>
|
||||
* Higher (larger numerical) priorities override lower (smaller numerical) priorities. <br>
|
||||
* For most developers this can be left at the default.
|
||||
*
|
||||
* @return The priority of this interface, the lowest legal value is {@link IOverrideInjector#MIN_NON_CORE_OVERRIDE_PRIORITY}.
|
||||
*/
|
||||
default int getPriority() { return IOverrideInjector.DEFAULT_NON_CORE_OVERRIDE_PRIORITY; }
|
||||
|
||||
|
||||
+8
-4
@@ -61,10 +61,14 @@ public abstract class AbstractDhApiChunkWorldGenerator implements Closeable, IDh
|
||||
/**
|
||||
* This method is called to generate terrain over a given area
|
||||
* from a thread defined by Distant Horizons. <br><br>
|
||||
*
|
||||
* See {@link IDhApiWorldGenerator#generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer) IDhApiWorldGenerator.generateChunks}
|
||||
* for the list of Object's this method should return along with additional documentation.
|
||||
*
|
||||
*
|
||||
* @param chunkPosX the chunk X position in the level (not to be confused with the chunk's BlockPos in the level)
|
||||
* @param chunkPosZ the chunk Z position in the level (not to be confused with the chunk's BlockPos in the level)
|
||||
* @param generatorMode how far into the world gen pipeline this method run. See {@link EDhApiDistantGeneratorMode} for additional documentation.
|
||||
*
|
||||
* @return See {@link IDhApiWorldGenerator#generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer) IDhApiWorldGenerator.generateChunks}
|
||||
* for the list of Object's this method should return along with additional documentation.
|
||||
*
|
||||
* @see IDhApiWorldGenerator#generateChunks(int, int, byte, byte, EDhApiDistantGeneratorMode, ExecutorService, Consumer) IDhApiWorldGenerator#generateChunks
|
||||
*/
|
||||
public abstract Object[] generateChunk(int chunkPosX, int chunkPosZ, EDhApiDistantGeneratorMode generatorMode);
|
||||
|
||||
+15
-6
@@ -28,7 +28,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
|
||||
*
|
||||
* TODO: System currently only supports 1x1 block per data.
|
||||
*
|
||||
* @see EDhApiDetailLevel
|
||||
* @see EDhApiDetailLevel
|
||||
*/
|
||||
default byte getSmallestDataDetailLevel() { return EDhApiDetailLevel.BLOCK.detailLevel; }
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
|
||||
* Default detail level is 0 <br>
|
||||
* For more information on what detail levels represent see: {@link EDhApiDetailLevel}.
|
||||
*
|
||||
* @see EDhApiDetailLevel
|
||||
* @see EDhApiDetailLevel
|
||||
*/
|
||||
default byte getLargestDataDetailLevel() { return EDhApiDetailLevel.BLOCK.detailLevel; }
|
||||
|
||||
@@ -49,7 +49,7 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
|
||||
* Default detail level is 4 <br>
|
||||
* For more information on what detail levels represent see: {@link EDhApiDetailLevel}.
|
||||
*
|
||||
* @see EDhApiDetailLevel
|
||||
* @see EDhApiDetailLevel
|
||||
*/
|
||||
default byte getMinGenerationGranularity() { return EDhApiDetailLevel.CHUNK.detailLevel; }
|
||||
|
||||
@@ -61,11 +61,11 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
|
||||
* Default detail level is 6 (4x4 chunks) <br>
|
||||
* For more information on what detail levels represent see: {@link EDhApiDetailLevel}.
|
||||
*
|
||||
* @see EDhApiDetailLevel
|
||||
* @see EDhApiDetailLevel
|
||||
*/
|
||||
default byte getMaxGenerationGranularity() { return (byte) (EDhApiDetailLevel.CHUNK.detailLevel + 2); }
|
||||
|
||||
/** Returns true if the generator is unable to accept new generation requests. */
|
||||
/** @return true if the generator is unable to accept new generation requests. */
|
||||
boolean isBusy();
|
||||
|
||||
|
||||
@@ -81,13 +81,22 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
|
||||
* After a chunk has been generated it (and any necessary supporting objects as listed below) should be passed into the
|
||||
* resultConsumer's {@link Consumer#accept} method. If the Consumer is given the wrong data
|
||||
* type(s) it will disable the world generator and log an error with a list of objects it was expecting. <br>
|
||||
* <strong>Note:</strong> these objects are minecraft version dependent and will change without notice!
|
||||
* <strong>Note:</strong> these objects are minecraft version dependent and <i>will</i> change without notice!
|
||||
* Please run your generator in game at least once to confirm the objects you are returning are correct. <br><br>
|
||||
*
|
||||
* Consumer expected inputs for each minecraft version (in order): <br>
|
||||
* <strong>1.16</strong>, <strong>1.17</strong>, <strong>1.18</strong>, <strong>1.19</strong>, <strong>1.20</strong>: <br>
|
||||
* - [net.minecraft.world.level.chunk.ChunkAccess] <br>
|
||||
* - [net.minecraft.world.level.ServerLevel] or [net.minecraft.world.level.ClientLevel] <br>
|
||||
*
|
||||
* @param chunkPosMinX the chunk X position closest to negative infinity
|
||||
* @param chunkPosMinZ the chunk Z position closest to negative infinity
|
||||
* @param granularity TODO find a central location to store the definition of granularity. For now it is stored in the Core method: WorldGenerationQueue#startGenerationEvent
|
||||
* @param targetDataDetail the LOD Detail level requested to generate. See {@link EDhApiDetailLevel} for additional information.
|
||||
* @param generatorMode how far into the world gen pipeline this method run. See {@link EDhApiDistantGeneratorMode} for additional documentation.
|
||||
* @param worldGeneratorThreadPool the thread pool that should be used when generating the returned {@link CompletableFuture}.
|
||||
* @param resultConsumer the consumer that should be fired whenever a chunk finishes generating.
|
||||
* @return a future that should run on the worldGeneratorThreadPool and complete once the given generation task has completed.
|
||||
*/
|
||||
CompletableFuture<Void> generateChunks(
|
||||
int chunkPosMinX, int chunkPosMinZ,
|
||||
|
||||
+13
-1
@@ -5,6 +5,8 @@ import com.seibel.distanthorizons.coreapi.interfaces.config.IConfigEntry;
|
||||
import com.seibel.distanthorizons.coreapi.interfaces.config.IConverter;
|
||||
import com.seibel.distanthorizons.coreapi.util.converters.DefaultConverter;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A wrapper used to interface with Distant Horizon's Config. <br> <br>
|
||||
*
|
||||
@@ -68,8 +70,18 @@ public class DhApiConfigValue<coreType, apiType> implements IDhApiConfigValue<ap
|
||||
|
||||
public boolean getCanBeOverrodeByApi() { return this.configEntry.getAllowApiOverride(); }
|
||||
|
||||
public apiType getDefaultValue() { return this.configConverter.convertToApiType(configEntry.getDefaultValue()); }
|
||||
public apiType getDefaultValue() { return this.configConverter.convertToApiType(this.configEntry.getDefaultValue()); }
|
||||
public apiType getMaxValue() { return this.configConverter.convertToApiType(this.configEntry.getMax()); }
|
||||
public apiType getMinValue() { return this.configConverter.convertToApiType(this.configEntry.getMin()); }
|
||||
|
||||
|
||||
public void addChangeListener(Consumer<apiType> onValueChangeFunc)
|
||||
{
|
||||
this.configEntry.addValueChangeListener((coreValue) ->
|
||||
{
|
||||
apiType apiValue = this.configConverter.convertToApiType(coreValue);
|
||||
onValueChangeFunc.accept(apiValue);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -172,6 +172,15 @@ public class ApiEventInjector extends DependencyInjector<IDhApiEvent> implements
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wraps the event parameter object in a {@link DhApiCancelableEventParam} or {@link DhApiEventParam} depending on
|
||||
* if it should allow cancellation or not.
|
||||
*
|
||||
* @param event the event instance
|
||||
* @param parameter the event's parameter object
|
||||
* @param <T> the event parameter type
|
||||
* @return the event parameter wrapped in a {@link DhApiCancelableEventParam} or {@link DhApiEventParam}
|
||||
*/
|
||||
public static <T> DhApiEventParam<T> createEventParamWrapper(IDhApiEvent<T> event, T parameter)
|
||||
{
|
||||
return (event instanceof IDhApiCancelableEvent) ? new DhApiCancelableEventParam<>(parameter) : new DhApiEventParam<>(parameter);
|
||||
|
||||
+4
@@ -1,6 +1,8 @@
|
||||
package com.seibel.distanthorizons.coreapi.interfaces.config;
|
||||
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Use for making the config variables
|
||||
*
|
||||
@@ -56,4 +58,6 @@ public interface IConfigEntry<T>
|
||||
/** Is the value of this equal to another */
|
||||
boolean equals(IConfigEntry<?> obj);
|
||||
|
||||
void addValueChangeListener(Consumer<T> onValueChangeFunc);
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public interface IDependencyInjector<BindableType extends IBindable>
|
||||
|
||||
|
||||
/**
|
||||
* This does not return incomplete dependencies. <Br>
|
||||
* Does not return incomplete dependencies. <Br>
|
||||
* See {@link #get(Class, boolean) get(Class, boolean)} for full documentation.
|
||||
*
|
||||
* @see #get(Class, boolean)
|
||||
|
||||
+2
-2
@@ -7,12 +7,12 @@ public interface IOverrideInjector<BindableType extends IBindable>
|
||||
{
|
||||
/**
|
||||
* All core overrides should have this priority. <Br>
|
||||
* Should be lower than MIN_OVERRIDE_PRIORITY.
|
||||
* Should be lower than {@link IOverrideInjector#MIN_NON_CORE_OVERRIDE_PRIORITY}.
|
||||
*/
|
||||
public static final int CORE_PRIORITY = -1;
|
||||
/**
|
||||
* The lowest priority non-core overrides can have.
|
||||
* Should be higher than CORE_PRIORITY.
|
||||
* Should be higher than {@link IOverrideInjector#CORE_PRIORITY}.
|
||||
*/
|
||||
public static final int MIN_NON_CORE_OVERRIDE_PRIORITY = 0;
|
||||
/** The priority given to overrides that don't explicitly define a priority. */
|
||||
|
||||
@@ -29,7 +29,6 @@ public class Initializer
|
||||
Class<?> compressor = LZ4Compressor.class;
|
||||
Class<?> networking = ByteBuf.class;
|
||||
Class<?> toml = com.electronwill.nightconfig.core.Config.class;
|
||||
Class<?> flatlaf = com.formdev.flatlaf.FlatDarculaLaf.class;
|
||||
}
|
||||
catch (NoClassDefFoundError e)
|
||||
{
|
||||
|
||||
@@ -152,7 +152,6 @@ public class Config
|
||||
+ "\n"
|
||||
+ "Lowest Quality: " + EMaxHorizontalResolution.CHUNK + "\n"
|
||||
+ "Highest Quality: " + EMaxHorizontalResolution.BLOCK)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.setPerformance(EConfigEntryPerformance.MEDIUM)
|
||||
.build();
|
||||
|
||||
@@ -173,7 +172,6 @@ public class Config
|
||||
+ "Lowest Quality: " + EVerticalQuality.HEIGHT_MAP + "\n"
|
||||
+ "Highest Quality: " + EVerticalQuality.EXTREME)
|
||||
.setPerformance(EConfigEntryPerformance.VERY_HIGH)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> ssao = new ConfigEntry.Builder<Boolean>()
|
||||
@@ -200,7 +198,6 @@ public class Config
|
||||
+ ETransparency.DISABLED + ": LODs will be opaque. \n"
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.MEDIUM)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EBlocksToAvoid> blocksToIgnore = new ConfigEntry.Builder<EBlocksToAvoid>()
|
||||
@@ -212,7 +209,6 @@ public class Config
|
||||
+ EBlocksToAvoid.NON_COLLIDING + ": Only represent solid blocks in the LODs (tall grass, torches, etc. won't count for a LOD's height) \n"
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> tintWithAvoidedBlocks = new ConfigEntry.Builder<Boolean>()
|
||||
@@ -224,7 +220,6 @@ public class Config
|
||||
+ "False: skipped blocks will not change color of surface below them. "
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
// TODO fixme
|
||||
@@ -532,7 +527,6 @@ public class Config
|
||||
+ "0 = black \n"
|
||||
+ "1 = normal \n"
|
||||
+ "2 = near white")
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Double> saturationMultiplier = new ConfigEntry.Builder<Double>() // TODO: Make this a float (the ClassicConfigGUI doesnt support floats)
|
||||
@@ -543,7 +537,6 @@ public class Config
|
||||
+ "0 = black and white \n"
|
||||
+ "1 = normal \n"
|
||||
+ "2 = very saturated")
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> enableCaveCulling = new ConfigEntry.Builder<Boolean>()
|
||||
@@ -601,7 +594,6 @@ public class Config
|
||||
+ ELodShading.NONE + ": All LOD sides will be rendered with the same brightness. \n"
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
}
|
||||
@@ -1242,6 +1234,7 @@ public class Config
|
||||
ThreadPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||
RenderQualityPresetConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||
QuickRenderToggleConfigEventHandler.INSTANCE.setUiOnlyConfigValues();
|
||||
RenderCacheConfigEventHandler.getInstance();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
+38
-11
@@ -1,9 +1,12 @@
|
||||
package com.seibel.distanthorizons.core.config.eventHandlers;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.api.enums.config.EBlocksToAvoid;
|
||||
import com.seibel.distanthorizons.api.enums.config.ELodShading;
|
||||
import com.seibel.distanthorizons.api.enums.config.EMaxHorizontalResolution;
|
||||
import com.seibel.distanthorizons.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.ETransparency;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
|
||||
@@ -16,28 +19,52 @@ import java.util.TimerTask;
|
||||
*
|
||||
* Note: if additional settings should clear the render cache, add those to this listener, don't create a new listener
|
||||
*/
|
||||
public class RenderCacheConfigEventHandler implements IConfigListener
|
||||
public class RenderCacheConfigEventHandler
|
||||
{
|
||||
public static RenderCacheConfigEventHandler INSTANCE = new RenderCacheConfigEventHandler();
|
||||
private static RenderCacheConfigEventHandler INSTANCE;
|
||||
|
||||
|
||||
// previous values used to check if a watched setting was actually modified
|
||||
private final ConfigChangeListener<EMaxHorizontalResolution> horizontalResolutionChangeListener;
|
||||
private final ConfigChangeListener<EVerticalQuality> verticalQualityChangeListener;
|
||||
private final ConfigChangeListener<ETransparency> transparencyChangeListener;
|
||||
private final ConfigChangeListener<EBlocksToAvoid> blocksToIgnoreChangeListener;
|
||||
private final ConfigChangeListener<Boolean> tintWithAvoidedBlocksChangeListener;
|
||||
|
||||
private final ConfigChangeListener<Double> brightnessMultiplierChangeListener;
|
||||
private final ConfigChangeListener<Double> saturationMultiplierChangeListener;
|
||||
private final ConfigChangeListener<ELodShading> lodShadingChangeListener;
|
||||
|
||||
/** how long to wait in milliseconds before applying the config changes */
|
||||
private static final long TIMEOUT_IN_MS = 4_000L;
|
||||
private Timer cacheClearingTimer;
|
||||
|
||||
|
||||
/** private since we only ever need one handler at a time */
|
||||
private RenderCacheConfigEventHandler() { }
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onConfigValueSet()
|
||||
public static RenderCacheConfigEventHandler getInstance()
|
||||
{
|
||||
this.refreshRenderDataAfterTimeout();
|
||||
if (INSTANCE == null)
|
||||
{
|
||||
INSTANCE = new RenderCacheConfigEventHandler();
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUiModify() { /* do nothing, we only care about modified config values */ }
|
||||
/** private since we only ever need one handler at a time */
|
||||
private RenderCacheConfigEventHandler()
|
||||
{
|
||||
this.horizontalResolutionChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.maxHorizontalResolution, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
this.verticalQualityChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.verticalQuality, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
this.transparencyChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.transparency, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
this.blocksToIgnoreChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.blocksToIgnore, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
this.tintWithAvoidedBlocksChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
|
||||
this.brightnessMultiplierChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.AdvancedGraphics.brightnessMultiplier, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
this.saturationMultiplierChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.AdvancedGraphics.saturationMultiplier, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
this.lodShadingChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading, (newValue) -> this.refreshRenderDataAfterTimeout());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Calling this method multiple times will reset the timer */
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ package com.seibel.distanthorizons.core.config.listeners;
|
||||
public interface IConfigListener
|
||||
{
|
||||
/** Called whenever the value is set (including in core DH code) */
|
||||
default void onConfigValueSet() {};
|
||||
default void onConfigValueSet() {}
|
||||
|
||||
/** Called whenever the value is changed through the UI */
|
||||
default void onUiModify() {};
|
||||
default void onUiModify() {}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.config.types;
|
||||
|
||||
|
||||
import com.seibel.distanthorizons.core.config.NumberUtil;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
|
||||
import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryAppearance;
|
||||
import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryPerformance;
|
||||
@@ -9,6 +10,7 @@ import com.seibel.distanthorizons.coreapi.interfaces.config.IConfigEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Use for making the config variables
|
||||
@@ -166,7 +168,16 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
/** Gets the performance impact of an option */
|
||||
public EConfigEntryPerformance getPerformance() { return this.performance; }
|
||||
|
||||
/** Fired whenever the config value changes to a new value. */
|
||||
public void addValueChangeListener(Consumer<T> onValueChangeFunc)
|
||||
{
|
||||
ConfigChangeListener<T> changeListener = new ConfigChangeListener<>(this, onValueChangeFunc);
|
||||
this.addListener(changeListener);
|
||||
}
|
||||
/** Fired whenever the config value is updated, including when the value doesn't change (IE when the UI changes state or the config is reloaded). */
|
||||
public void addListener(IConfigListener newListener) { this.listenerList.add(newListener); }
|
||||
|
||||
//public void removeValueChangeListener(Consumer<T> onValueChangeFunc) { } // not currently implemented
|
||||
public void removeListener(IConfigListener oldListener) { this.listenerList.remove(oldListener); }
|
||||
|
||||
public void clearListeners() { this.listenerList.clear(); }
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
this.incompleteDataSources.put(pos, dataSource);
|
||||
// queue this section to be generated
|
||||
GenTask genTask = new GenTask(pos, new WeakReference<>(dataSource));
|
||||
worldGenQueue.submitGenTask(new DhLodPos(pos), dataSource.getDataDetailLevel(), genTask)
|
||||
worldGenQueue.submitGenTask(pos, dataSource.getDataDetailLevel(), genTask)
|
||||
.whenComplete((genTaskResult, ex) ->
|
||||
{
|
||||
if (genTaskResult.success)
|
||||
|
||||
+1
-1
@@ -447,7 +447,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
|
||||
// Skip updating the cache if the data file is already up-to-date
|
||||
FullDataMetaFile dataFile = this.fullDataSourceProvider.getFileIfExist(file.pos);
|
||||
if (!ALWAYS_INVALIDATE_CACHE && dataFile != null && dataFile.baseMetaData.checksum == file.baseMetaData.dataVersion.get()) {
|
||||
if (!ALWAYS_INVALIDATE_CACHE && dataFile != null && dataFile.baseMetaData != null && dataFile.baseMetaData.checksum == file.baseMetaData.dataVersion.get()) {
|
||||
LOGGER.debug("Skipping render cache update for {}", file.pos);
|
||||
renderSource.localVersion.incrementAndGet();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ public interface IWorldGenerationQueue extends Closeable
|
||||
/** the largest numerical detail level */
|
||||
byte largestDataDetail();
|
||||
|
||||
CompletableFuture<WorldGenResult> submitGenTask(DhLodPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker);
|
||||
CompletableFuture<WorldGenResult> submitGenTask(DhSectionPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker);
|
||||
void cancelGenTasks(Iterable<DhSectionPos> positions);
|
||||
|
||||
/** @param targetPos the position that world generation should be centered around, generally this will be the player's position. */
|
||||
|
||||
+18
-19
@@ -41,9 +41,9 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
|
||||
/** contains the positions that need to be generated */
|
||||
//private final QuadTree<WorldGenTask> waitingTaskQuadTree;
|
||||
private final ConcurrentHashMap<DhLodPos, WorldGenTask> waitingTasks = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<DhSectionPos, WorldGenTask> waitingTasks = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentHashMap<DhLodPos, InProgressWorldGenTaskGroup> inProgressGenTasksByLodPos = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<DhSectionPos, InProgressWorldGenTaskGroup> inProgressGenTasksByLodPos = new ConcurrentHashMap<>();
|
||||
|
||||
// granularity is the detail level for batching world generator requests together
|
||||
public final byte maxGranularity;
|
||||
@@ -73,8 +73,8 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
// debug variables to test for duplicate world generator requests //
|
||||
/** limits how many of the previous world gen requests we should track */
|
||||
private static final int MAX_ALREADY_GENERATED_COUNT = 100;
|
||||
private final HashMap<DhLodPos, StackTraceElement[]> alreadyGeneratedPosHashSet = new HashMap<>(MAX_ALREADY_GENERATED_COUNT);
|
||||
private final Queue<DhLodPos> alreadyGeneratedPosQueue = new LinkedList<>();
|
||||
private final HashMap<DhSectionPos, StackTraceElement[]> alreadyGeneratedPosHashSet = new HashMap<>(MAX_ALREADY_GENERATED_COUNT);
|
||||
private final Queue<DhSectionPos> alreadyGeneratedPosQueue = new LinkedList<>();
|
||||
|
||||
private static RateLimitedThreadPoolExecutor worldGeneratorThreadPool;
|
||||
private static ConfigChangeListener<Integer> configListener;
|
||||
@@ -119,7 +119,8 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
// task handling //
|
||||
//=================//
|
||||
|
||||
public CompletableFuture<WorldGenResult> submitGenTask(DhLodPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker)
|
||||
@Override
|
||||
public CompletableFuture<WorldGenResult> submitGenTask(DhSectionPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker)
|
||||
{
|
||||
// the generator is shutting down, don't add new tasks
|
||||
if (this.generatorClosingFuture != null)
|
||||
@@ -139,9 +140,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
}
|
||||
|
||||
// Assert that the data at least can fill in 1 single ChunkSizedFullDataAccessor
|
||||
LodUtil.assertTrue(pos.detailLevel > requiredDataDetail + LodUtil.CHUNK_DETAIL_LEVEL);
|
||||
|
||||
DhSectionPos requestPos = new DhSectionPos(pos.detailLevel, pos.x, pos.z);
|
||||
LodUtil.assertTrue(pos.sectionDetailLevel > requiredDataDetail + LodUtil.CHUNK_DETAIL_LEVEL);
|
||||
|
||||
|
||||
//if (this.waitingTaskQuadTree.isSectionPosInBounds(requestPos))
|
||||
@@ -330,7 +329,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
}
|
||||
|
||||
Mapper closestTaskMap = waitingTasks.reduceEntries(1024,
|
||||
v -> new Mapper(v.getValue(), v.getValue().pos.getCenterBlockPos().toPos2D().chebyshevDist(targetPos.toPos2D())),
|
||||
v -> new Mapper(v.getValue(), v.getValue().pos.getSectionBBoxPos().getCenterBlockPos().toPos2D().chebyshevDist(targetPos.toPos2D())),
|
||||
(a, b) -> a.dist < b.dist ? a : b);
|
||||
|
||||
closestTask = closestTaskMap.task;
|
||||
@@ -375,14 +374,14 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
|
||||
// split up the task and add each one to the tree
|
||||
LinkedList<CompletableFuture<WorldGenResult>> childFutures = new LinkedList<>();
|
||||
DhSectionPos sectionPos = new DhSectionPos(closestTask.pos.detailLevel, closestTask.pos.x, closestTask.pos.z);
|
||||
DhSectionPos sectionPos = new DhSectionPos(closestTask.pos.sectionDetailLevel, closestTask.pos.sectionX, closestTask.pos.sectionZ);
|
||||
WorldGenTask finalClosestTask = closestTask;
|
||||
sectionPos.forEachChild((childDhSectionPos) ->
|
||||
{
|
||||
CompletableFuture<WorldGenResult> newFuture = new CompletableFuture<>();
|
||||
childFutures.add(newFuture);
|
||||
|
||||
WorldGenTask newGenTask = new WorldGenTask(new DhLodPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ), childDhSectionPos.sectionDetailLevel, finalClosestTask.taskTracker, newFuture);
|
||||
WorldGenTask newGenTask = new WorldGenTask(childDhSectionPos, childDhSectionPos.sectionDetailLevel, finalClosestTask.taskTracker, newFuture);
|
||||
waitingTasks.put(newGenTask.pos, newGenTask);
|
||||
//this.waitingTaskQuadTree.setValue(new DhSectionPos(childDhSectionPos.sectionDetailLevel, childDhSectionPos.sectionX, childDhSectionPos.sectionZ), newGenTask);
|
||||
|
||||
@@ -402,12 +401,12 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
private void startWorldGenTaskGroup(InProgressWorldGenTaskGroup inProgressTaskGroup)
|
||||
{
|
||||
byte taskDetailLevel = inProgressTaskGroup.group.dataDetail;
|
||||
DhLodPos taskPos = inProgressTaskGroup.group.pos;
|
||||
byte granularity = (byte) (taskPos.detailLevel - taskDetailLevel);
|
||||
DhSectionPos taskPos = inProgressTaskGroup.group.pos;
|
||||
byte granularity = (byte) (taskPos.sectionDetailLevel - taskDetailLevel);
|
||||
LodUtil.assertTrue(granularity >= this.minGranularity && granularity <= this.maxGranularity);
|
||||
LodUtil.assertTrue(taskDetailLevel >= this.smallestDataDetail && taskDetailLevel <= this.largestDataDetail);
|
||||
|
||||
DhChunkPos chunkPosMin = new DhChunkPos(taskPos.getCornerBlockPos());
|
||||
DhChunkPos chunkPosMin = new DhChunkPos(taskPos.getSectionBBoxPos().getCornerBlockPos());
|
||||
|
||||
// check if this is a duplicate generation task
|
||||
if (this.alreadyGeneratedPosHashSet.containsKey(inProgressTaskGroup.group.pos))
|
||||
@@ -418,7 +417,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
//StackTraceElement[] stackTrace = this.alreadyGeneratedPosHashSet.get(inProgressTaskGroup.group.pos);
|
||||
|
||||
// sending a success result is necessary to make sure the render sections are reloaded correctly
|
||||
inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos))));
|
||||
inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos.sectionX, taskPos.sectionZ))));
|
||||
return;
|
||||
}
|
||||
this.alreadyGeneratedPosHashSet.put(inProgressTaskGroup.group.pos, Thread.currentThread().getStackTrace());
|
||||
@@ -427,7 +426,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
// remove extra tracked duplicate positions
|
||||
while (this.alreadyGeneratedPosQueue.size() > MAX_ALREADY_GENERATED_COUNT)
|
||||
{
|
||||
DhLodPos posToRemove = this.alreadyGeneratedPosQueue.poll();
|
||||
DhSectionPos posToRemove = this.alreadyGeneratedPosQueue.poll();
|
||||
this.alreadyGeneratedPosHashSet.remove(posToRemove);
|
||||
}
|
||||
|
||||
@@ -452,7 +451,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
else
|
||||
{
|
||||
//LOGGER.info("Section generation at "+pos+" completed");
|
||||
inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos))));
|
||||
inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos.sectionX, taskPos.sectionZ))));
|
||||
}
|
||||
boolean worked = this.inProgressGenTasksByLodPos.remove(taskPos, inProgressTaskGroup);
|
||||
LodUtil.assertTrue(worked);
|
||||
@@ -666,9 +665,9 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
private boolean canGeneratePos(byte worldGenTaskGroupDetailLevel /*when in doubt use 0*/ , DhLodPos taskPos)
|
||||
private boolean canGeneratePos(byte worldGenTaskGroupDetailLevel /*when in doubt use 0*/ , DhSectionPos taskPos)
|
||||
{
|
||||
byte granularity = (byte) (taskPos.detailLevel - worldGenTaskGroupDetailLevel);
|
||||
byte granularity = (byte) (taskPos.sectionDetailLevel - worldGenTaskGroupDetailLevel);
|
||||
return (granularity >= this.minGranularity && granularity <= this.maxGranularity);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
package com.seibel.distanthorizons.core.generation.tasks;
|
||||
|
||||
import com.seibel.distanthorizons.core.pos.DhLodPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -10,14 +11,14 @@ import java.util.concurrent.CompletableFuture;
|
||||
*/
|
||||
public final class WorldGenTask
|
||||
{
|
||||
public final DhLodPos pos;
|
||||
public final DhSectionPos pos;
|
||||
public final byte dataDetailLevel;
|
||||
public final IWorldGenTaskTracker taskTracker;
|
||||
public final CompletableFuture<WorldGenResult> future;
|
||||
|
||||
|
||||
|
||||
public WorldGenTask(DhLodPos pos, byte dataDetail, IWorldGenTaskTracker taskTracker, CompletableFuture<WorldGenResult> future)
|
||||
public WorldGenTask(DhSectionPos pos, byte dataDetail, IWorldGenTaskTracker taskTracker, CompletableFuture<WorldGenResult> future)
|
||||
{
|
||||
this.dataDetailLevel = dataDetail;
|
||||
this.pos = pos;
|
||||
|
||||
+3
-2
@@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.generation.tasks;
|
||||
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.distanthorizons.core.pos.DhLodPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
@@ -13,14 +14,14 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public final class WorldGenTaskGroup
|
||||
{
|
||||
public final DhLodPos pos;
|
||||
public final DhSectionPos pos;
|
||||
public byte dataDetail;
|
||||
/** Only accessed by the generator polling thread */
|
||||
public final LinkedList<WorldGenTask> worldGenTasks = new LinkedList<>();
|
||||
|
||||
|
||||
|
||||
public WorldGenTaskGroup(DhLodPos pos, byte dataDetail)
|
||||
public WorldGenTaskGroup(DhSectionPos pos, byte dataDetail)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.dataDetail = dataDetail;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.seibel.distanthorizons.core.jar.gui;
|
||||
|
||||
import com.formdev.flatlaf.FlatDarkLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.extras.FlatSVGIcon;
|
||||
import com.seibel.distanthorizons.core.jar.JarUtils;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
|
||||
@@ -13,6 +10,7 @@ import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
@@ -41,7 +39,7 @@ public class BaseJFrame extends JFrame
|
||||
setTitle(SingletonInjector.INSTANCE.get(ILangWrapper.class).getLang("lod.title"));
|
||||
try
|
||||
{
|
||||
setIconImage(new FlatSVGIcon(JarUtils.accessFile("iconLegacy.svg")).getImage()); // SVG Salamander (the library which we use for svg files) doesn't support css class colors
|
||||
setIconImage(ImageIO.read(JarUtils.accessFile("icon.png")));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -96,7 +94,8 @@ public class BaseJFrame extends JFrame
|
||||
add(languageBox);
|
||||
|
||||
|
||||
// ========== THEMING ==========
|
||||
// ========== THEMING ========== //
|
||||
/**
|
||||
// TODO: Change the theme to a toggle switch rather than having 2 buttons
|
||||
int themeButtonSize = 25;
|
||||
JButton lightMode = null;
|
||||
@@ -132,6 +131,7 @@ public class BaseJFrame extends JFrame
|
||||
// Finally add the buttons
|
||||
add(lightMode);
|
||||
add(darkMode);
|
||||
*/
|
||||
}
|
||||
|
||||
public BaseJFrame addLogo()
|
||||
|
||||
@@ -287,9 +287,6 @@ public class LodRenderer
|
||||
{
|
||||
profiler.popPush("LOD SSAO");
|
||||
SSAORenderer.INSTANCE.render(partialTicks);
|
||||
|
||||
// TODO: Fix this file (or check the result is the same) so that SSAORenderer could be deleted
|
||||
//SSAOShader.INSTANCE.render(partialTicks); // For some reason this looks slightly different :/
|
||||
}
|
||||
|
||||
|
||||
|
||||
-1
@@ -30,7 +30,6 @@ public class FogShader extends AbstractShaderRenderer
|
||||
public final int fogVerticalScaleUniform;
|
||||
public final int nearFogStartUniform;
|
||||
public final int nearFogLengthUniform;
|
||||
;
|
||||
public final int fullFogModeUniform;
|
||||
|
||||
|
||||
|
||||
+117
-68
@@ -16,18 +16,13 @@ import org.lwjgl.opengl.GL32;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
// TODO: Move over to SSAOShader
|
||||
// For some reason this version looks slightly different to that, even tough there isnt much visible change in the code
|
||||
public class SSAORenderer
|
||||
{
|
||||
public static SSAORenderer INSTANCE = new SSAORenderer();
|
||||
|
||||
public SSAORenderer()
|
||||
{
|
||||
}
|
||||
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
private static final int MAX_KERNEL_SIZE = 128;
|
||||
private static final float[] box_vertices = {
|
||||
-1, -1,
|
||||
1, -1,
|
||||
@@ -37,67 +32,115 @@ public class SSAORenderer
|
||||
-1, 1,
|
||||
};
|
||||
|
||||
ShaderProgram ssaoShader;
|
||||
ShaderProgram applyShader;
|
||||
GLVertexBuffer boxBuffer;
|
||||
VertexAttribute va;
|
||||
boolean init = false;
|
||||
|
||||
private static final int MAX_KERNEL_SIZE = 32;
|
||||
|
||||
private ShaderProgram ssaoShader;
|
||||
private ShaderProgram applyShader;
|
||||
private GLVertexBuffer boxBuffer;
|
||||
private VertexAttribute va;
|
||||
private boolean init = false;
|
||||
|
||||
private float[] kernel = new float[MAX_KERNEL_SIZE * 3];
|
||||
|
||||
public void init()
|
||||
{
|
||||
if (init) return;
|
||||
|
||||
init = true;
|
||||
va = VertexAttribute.create();
|
||||
va.bind();
|
||||
// Pos
|
||||
va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
|
||||
va.completeAndCheck(Float.BYTES * 2);
|
||||
ssaoShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
|
||||
"fragColor", new String[]{"vPosition"});
|
||||
|
||||
applyShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag",
|
||||
"fragColor", new String[]{"vPosition"});
|
||||
|
||||
|
||||
// Generate kernel
|
||||
kernel = genKernel();
|
||||
// Framebuffer
|
||||
createBuffer();
|
||||
}
|
||||
|
||||
private int width = -1;
|
||||
private int height = -1;
|
||||
private int ssaoFramebuffer = -1;
|
||||
|
||||
private int ssaoTexture = -1;
|
||||
|
||||
// ssao uniforms
|
||||
private final SsaoShaderUniforms ssaoShaderUniforms = new SsaoShaderUniforms();
|
||||
private static class SsaoShaderUniforms
|
||||
{
|
||||
public int gProjUniform;
|
||||
public int gSampleRadUniform;
|
||||
public int gFactorUniform;
|
||||
public int gPowerUniform;
|
||||
public int gKernelUniform;
|
||||
public int gDepthMapUniform;
|
||||
}
|
||||
|
||||
// apply uniforms
|
||||
private final ApplyShaderUniforms applyShaderUniforms = new ApplyShaderUniforms();
|
||||
private static class ApplyShaderUniforms
|
||||
{
|
||||
public int gSSAOMapUniform;
|
||||
public int gDepthMapUniform;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
private SSAORenderer() { }
|
||||
|
||||
public void init()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.init = true;
|
||||
this.va = VertexAttribute.create();
|
||||
this.va.bind();
|
||||
// Pos
|
||||
this.va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
|
||||
this.va.completeAndCheck(Float.BYTES * 2);
|
||||
this.ssaoShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
|
||||
"fragColor", new String[]{"vPosition"});
|
||||
|
||||
this.applyShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag",
|
||||
"fragColor", new String[]{"vPosition"});
|
||||
|
||||
|
||||
|
||||
// SSAO uniform setup
|
||||
this.ssaoShaderUniforms.gProjUniform = this.ssaoShader.getUniformLocation("gProj");
|
||||
this.ssaoShaderUniforms.gSampleRadUniform = this.ssaoShader.getUniformLocation("gSampleRad");
|
||||
this.ssaoShaderUniforms.gFactorUniform = this.ssaoShader.getUniformLocation("gFactor");
|
||||
this.ssaoShaderUniforms.gPowerUniform = this.ssaoShader.getUniformLocation("gPower");
|
||||
this.ssaoShaderUniforms.gKernelUniform = this.ssaoShader.getUniformLocation("gKernel");
|
||||
this.ssaoShaderUniforms.gDepthMapUniform = this.ssaoShader.getUniformLocation("gDepthMap");
|
||||
|
||||
// Apply uniform setup
|
||||
this.applyShaderUniforms.gSSAOMapUniform = this.applyShader.getUniformLocation("gSSAOMap");
|
||||
this.applyShaderUniforms.gDepthMapUniform = this.applyShader.getUniformLocation("gDepthMap");
|
||||
|
||||
|
||||
|
||||
// Generate kernel
|
||||
this.kernel = genKernel();
|
||||
// Framebuffer
|
||||
this.createBuffer();
|
||||
}
|
||||
|
||||
private void createFramebuffer(int width, int height)
|
||||
{
|
||||
if (ssaoFramebuffer != -1)
|
||||
if (this.ssaoFramebuffer != -1)
|
||||
{
|
||||
GL32.glDeleteFramebuffers(ssaoFramebuffer);
|
||||
ssaoFramebuffer = -1;
|
||||
GL32.glDeleteFramebuffers(this.ssaoFramebuffer);
|
||||
this.ssaoFramebuffer = -1;
|
||||
}
|
||||
|
||||
if (ssaoTexture != -1)
|
||||
if (this.ssaoTexture != -1)
|
||||
{
|
||||
GL32.glDeleteTextures(ssaoTexture);
|
||||
ssaoTexture = -1;
|
||||
GL32.glDeleteTextures(this.ssaoTexture);
|
||||
this.ssaoTexture = -1;
|
||||
}
|
||||
|
||||
ssaoFramebuffer = GL32.glGenFramebuffers();
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, ssaoFramebuffer);
|
||||
this.ssaoFramebuffer = GL32.glGenFramebuffers();
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
|
||||
|
||||
ssaoTexture = GL32.glGenTextures();
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, ssaoTexture);
|
||||
this.ssaoTexture = GL32.glGenTextures();
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
|
||||
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RED, width, height, 0, GL32.GL_RED, GL32.GL_FLOAT, (ByteBuffer) null);
|
||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_NEAREST);
|
||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_NEAREST);
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, ssaoTexture, 0);
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.ssaoTexture, 0);
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
@@ -106,9 +149,9 @@ public class SSAORenderer
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
buffer.asFloatBuffer().put(box_vertices);
|
||||
buffer.rewind();
|
||||
boxBuffer = new GLVertexBuffer(false);
|
||||
boxBuffer.bind();
|
||||
boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
|
||||
this.boxBuffer = new GLVertexBuffer(false);
|
||||
this.boxBuffer.bind();
|
||||
this.boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
|
||||
}
|
||||
|
||||
private static float[] genKernel()
|
||||
@@ -140,11 +183,16 @@ public class SSAORenderer
|
||||
return kernel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// render //
|
||||
//========//
|
||||
|
||||
public void render(float partialTicks)
|
||||
{
|
||||
GLState state = new GLState();
|
||||
init();
|
||||
//GL32.glDepthMask(false);
|
||||
this.init();
|
||||
int width = MC_RENDER.getTargetFrameBufferViewportWidth();
|
||||
int height = MC_RENDER.getTargetFrameBufferViewportHeight();
|
||||
|
||||
@@ -152,10 +200,10 @@ public class SSAORenderer
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
createFramebuffer(width, height);
|
||||
this.createFramebuffer(width, height);
|
||||
}
|
||||
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, ssaoFramebuffer);
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
|
||||
GL32.glViewport(0, 0, width, height);
|
||||
GL32.glDisable(GL32.GL_DEPTH_TEST);
|
||||
GL32.glDisable(GL32.GL_BLEND);
|
||||
@@ -168,35 +216,36 @@ public class SSAORenderer
|
||||
RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks),
|
||||
(float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2)));
|
||||
|
||||
ssaoShader.bind();
|
||||
ssaoShader.setUniform(ssaoShader.getUniformLocation("gProj"), perspective);
|
||||
ssaoShader.setUniform(ssaoShader.getUniformLocation("gSampleRad"), 3.0f);
|
||||
ssaoShader.setUniform(ssaoShader.getUniformLocation("gFactor"), 0.8f);
|
||||
ssaoShader.setUniform(ssaoShader.getUniformLocation("gPower"), 1.0f);
|
||||
va.bind();
|
||||
va.bindBufferToAllBindingPoint(boxBuffer.getId());
|
||||
this.ssaoShader.bind();
|
||||
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective);
|
||||
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleRadUniform, 3.0f);
|
||||
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.8f);
|
||||
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 1.0f);
|
||||
|
||||
this.va.bind();
|
||||
this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId());
|
||||
|
||||
GL32.glActiveTexture(GL32.GL_TEXTURE0);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
|
||||
|
||||
GL32.glUniform3fv(ssaoShader.getUniformLocation("gKernel"), kernel);
|
||||
GL32.glUniform1i(ssaoShader.getUniformLocation("gDepthMap"), 0);
|
||||
GL32.glUniform3fv(this.ssaoShaderUniforms.gKernelUniform, this.kernel);
|
||||
GL32.glUniform1i(this.ssaoShaderUniforms.gDepthMapUniform, 0);
|
||||
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
|
||||
|
||||
|
||||
|
||||
applyShader.bind();
|
||||
this.applyShader.bind();
|
||||
|
||||
GL32.glEnable(GL11.GL_BLEND);
|
||||
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
|
||||
|
||||
GL32.glActiveTexture(GL32.GL_TEXTURE0);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, ssaoTexture);
|
||||
GL32.glUniform1i(applyShader.getUniformLocation("gSSAOMap"), 0);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
|
||||
GL32.glUniform1i(this.applyShaderUniforms.gSSAOMapUniform, 0);
|
||||
GL32.glActiveTexture(GL32.GL_TEXTURE1);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
|
||||
GL32.glUniform1i(applyShader.getUniformLocation("gDepthMap"), 1);
|
||||
GL32.glUniform1i(this.applyShaderUniforms.gDepthMapUniform, 1);
|
||||
|
||||
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
|
||||
|
||||
@@ -206,8 +255,8 @@ public class SSAORenderer
|
||||
|
||||
public void free()
|
||||
{
|
||||
ssaoShader.free();
|
||||
applyShader.free();
|
||||
this.ssaoShader.free();
|
||||
this.applyShader.free();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
package com.seibel.distanthorizons.core.render.renderer.shaders;
|
||||
|
||||
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
|
||||
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
public class SSAOShader extends AbstractShaderRenderer
|
||||
{
|
||||
public static SSAOShader INSTANCE = new SSAOShader();
|
||||
|
||||
private static final int MAX_KERNEL_SIZE = 32;
|
||||
private float[] kernel = new float[MAX_KERNEL_SIZE * 3];
|
||||
|
||||
|
||||
public SSAOShader()
|
||||
{
|
||||
super(
|
||||
new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
|
||||
"fragColor", new String[]{"vPosition"}),
|
||||
new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag",
|
||||
"fragColor", new String[]{"vPosition"})
|
||||
);
|
||||
|
||||
}
|
||||
@Override
|
||||
void postInit()
|
||||
{
|
||||
// Generate kernel
|
||||
kernel = genKernel();
|
||||
}
|
||||
|
||||
@Override
|
||||
void setVertexAttributes()
|
||||
{
|
||||
va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
void setShaderUniforms(float partialTicks)
|
||||
{
|
||||
Mat4f perspective = Mat4f.perspective(
|
||||
(float) MC_RENDER.getFov(partialTicks),
|
||||
MC_RENDER.getTargetFrameBufferViewportWidth() / (float) MC_RENDER.getTargetFrameBufferViewportHeight(),
|
||||
RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks),
|
||||
(float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2)));
|
||||
|
||||
this.shader.setUniform(this.shader.getUniformLocation("gProj"), perspective);
|
||||
this.shader.setUniform(this.shader.getUniformLocation("gSampleRad"), 3.0f);
|
||||
this.shader.setUniform(this.shader.getUniformLocation("gFactor"), 0.8f);
|
||||
this.shader.setUniform(this.shader.getUniformLocation("gPower"), 1.0f);
|
||||
|
||||
GL32.glUniform3fv(this.shader.getUniformLocation("gKernel"), kernel);
|
||||
GL32.glUniform1i(this.shader.getUniformLocation("gDepthMap"), 0);
|
||||
}
|
||||
|
||||
private static float[] genKernel()
|
||||
{
|
||||
float[] kernel = new float[MAX_KERNEL_SIZE * 3];
|
||||
for (int i = 0; i < MAX_KERNEL_SIZE; i++)
|
||||
{
|
||||
float sampleX = (float) (Math.random() * 2.0 - 1.0);
|
||||
float sampleY = (float) (Math.random() * 2.0 - 1.0);
|
||||
float sampleZ = (float) Math.random();
|
||||
|
||||
|
||||
// Normalize
|
||||
float magnitude = (float) Math.sqrt(Math.pow(sampleX, 2) + Math.pow(sampleY, 2) + Math.pow(sampleZ, 2));
|
||||
sampleX /= magnitude;
|
||||
sampleY /= magnitude;
|
||||
sampleZ /= magnitude;
|
||||
|
||||
float scale = i / (float) MAX_KERNEL_SIZE;
|
||||
float interpolatedScale = (float) (0.1 + (scale * scale) * (0.9));
|
||||
|
||||
sampleX *= interpolatedScale;
|
||||
sampleY *= interpolatedScale;
|
||||
sampleZ *= interpolatedScale;
|
||||
kernel[i * 3] = sampleX;
|
||||
kernel[i * 3 + 1] = sampleY;
|
||||
kernel[i * 3 + 2] = sampleZ;
|
||||
}
|
||||
return kernel;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,7 +10,7 @@ uniform float gFactor;
|
||||
uniform float gPower;
|
||||
uniform mat4 gProj;
|
||||
|
||||
const int MAX_KERNEL_SIZE = 32;
|
||||
const int MAX_KERNEL_SIZE = 128;
|
||||
const float INV_MAX_KERNEL_SIZE_F = 1.0 / float(MAX_KERNEL_SIZE);
|
||||
const vec2 HALF_2 = vec2(0.5);
|
||||
uniform vec3 gKernel[MAX_KERNEL_SIZE];
|
||||
@@ -55,7 +55,7 @@ void main()
|
||||
|
||||
float rangeCheck = smoothstep(0.0, 1.0, gSampleRad / abs(viewPos.z - geometryDepth));
|
||||
// the number added to the samplePos.z can be used to reduce noise in the SSAO application at the cost of reducing the overall affect
|
||||
occlusion_factor += float(geometryDepth >= samplePos.z + 1.0) * rangeCheck;
|
||||
occlusion_factor += float(geometryDepth >= samplePos.z + 0.1) * rangeCheck;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user