Compare commits

..

6 Commits

Author SHA1 Message Date
Ran-Mewo acbd90ac5a Add instructions for downloading translations 2026-02-03 11:43:51 +11:00
Ran-Mewo 731d3f63fd Undo commiting translations 2026-02-03 10:17:50 +11:00
Ran-Mewo 909168d63b Do crowdin upload sources only when there's a change. 2026-01-27 01:30:58 +11:00
Ran-Mewo 235ab0e961 Make build dependent on translations 2026-01-24 22:58:01 +06:00
Ran-Mewo 152684bbee make the translations stage automatic 2026-01-24 22:23:20 +06:00
Ran-Mewo 50fe44ebf9 trans :3 lations 2026-01-24 21:49:49 +06:00
172 changed files with 1077 additions and 13759 deletions
+19
View File
@@ -3,7 +3,9 @@
image: eclipse-temurin:21
# all stages need to be defined here
# TODO: Make stages depend on what is in versionProperties
stages:
- translations
- build
- api
- pages
@@ -32,6 +34,9 @@ variables:
build:
stage: build
needs:
- job: translations
artifacts: true
parallel:
matrix:
- MC_VER: [
@@ -101,3 +106,17 @@ pages:
- public
allow_failure: false
extends: .build_java
translations:
stage: translations
needs: []
image: crowdin/cli:latest
script:
- if [ "$CI_COMMIT_BEFORE_SHA" = "0000000000000000000000000000000000000000" ] || git diff --name-only "$CI_COMMIT_BEFORE_SHA" "$CI_COMMIT_SHA" -- coreSubProjects/core/src/main/resources/assets/distanthorizons/lang | grep -q .; then crowdin upload sources; fi
- crowdin download --export-only-approved --skip-untranslated-files
- for f in coreSubProjects/core/src/main/resources/assets/distanthorizons/lang/*.json; do [ -e "$f" ] || continue; sed -i 's/\\\\n/\\n/g' "$f"; n="$(basename "$f" | tr '[:upper:]' '[:lower:]')"; [ "$(basename "$f")" = "$n" ] || mv "$f" "$(dirname "$f")/$n"; done
artifacts:
paths:
- coreSubProjects/core/src/main/resources/assets/distanthorizons/lang/**
expire_in: 1 day
when: always
+5
View File
@@ -12,6 +12,11 @@ Below is a video demonstrating the system:
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank">![Distant Horizons - Alpha 2.0](https://i.ytimg.com/vi/SxQdbtjGEsc/hqdefault.jpg)</a>
## Translations
[![Crowdin](https://badges.crowdin.net/distant-horizons/localized.svg)](https://crowdin.com/project/distant-horizons)\
Crowdin Project: [Distant Horizons](https://crowdin.com/project/distant-horizons)\
Guidelines: [translations.md](translations.md)
<br>
## Minecraft and Library Versions
+63 -17
View File
@@ -204,6 +204,15 @@ subprojects { p ->
developmentForge.extendsFrom coreProjects
if (findProject(":neoforge"))
developmentNeoForge.extendsFrom coreProjects
// TODO remove unused fabricLike
if (findProject(":fabricLike") && p != project(":fabricLike")) {
// Shadow fabricLike
fabricLike
shadowFabricLike
compileClasspath.extendsFrom fabricLike
runtimeClasspath.extendsFrom fabricLike
}
}
}
@@ -268,6 +277,11 @@ subprojects { p ->
// Netty
implementation("io.netty:netty-buffer:${rootProject.netty_version}")
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
}
//==========================//
@@ -304,6 +318,12 @@ subprojects { p ->
// Common
common(project(":common")) { transitive false }
shadowCommon(project(":common")) { transitive false }
// FabricLike
if (findProject(":fabricLike") && p != project(":fabricLike")) {
fabricLike(project(path: ":fabricLike")) { transitive false }
shadowFabricLike(project(path: ":fabricLike")) { transitive false }
}
}
}
@@ -313,9 +333,18 @@ subprojects { p ->
if (isMinecraftSubProject && p != project(":common")) {
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
if (findProject(":fabricLike") && p != project(":fabricLike")) {
configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject
relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location
}
}
def librariesLocation = "DistantHorizons.libraries"
// LWJGL
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
relocate "org.lwjgl.system.jawt", "${librariesLocation}.lwjgl.system.jawt"
// Compression (LZ4)
relocate "net.jpountz", "${librariesLocation}.jpountz"
@@ -365,6 +394,9 @@ subprojects { p ->
// NightConfig (includes Toml & Json)
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
// SVG (not needed atm)
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
// Netty
// Don't relocate, it causes problems with using MC's FriendlyByteBufs
// relocate "io.netty", "${librariesLocation}.netty"
@@ -376,10 +408,10 @@ subprojects { p ->
// Put stuff from gradle.properties into the mod info
// Note: these resources are only included in the mod jars, the core and API jars don't include these files
processResources {
def resourceTargets = [ // Location of where to inject the properties
// Holds info like git commit
// TODO: For some reason this script doesnt work with the core project
"build_info.json",
// Properties for each of the loaders
@@ -389,7 +421,7 @@ subprojects { p ->
"META-INF/neoforge.mods.toml",
// The mixins for each of the loaders
//"DistantHorizons."+ p.name +".fabricLike.mixins.json"
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
]
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
@@ -409,6 +441,9 @@ subprojects { p ->
quilt_contributors.reverse()
//println quilt_contributors.join(", ")
// TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
// println p.tasks.findByName('shadowJar')
// These "hasProperty"'s are so that they can be passed through the cli (ie in the CI)
try {
@@ -470,8 +505,13 @@ subprojects { p ->
// ==================== Delete un-needed files ====================
exclude "DistantHorizons.fabricLike.mixins.json" // This isnt required atm, but we will be using it later
// exclude "*.distanthorizons.accesswidener"
//// include "${accessWidenerVersion}.distanthorizons.accesswidener"
// Jank solution to remove all unused accesswideners
// (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
// The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
exclude { file ->
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
return true
@@ -614,36 +654,33 @@ allprojects { p ->
includeGroup "forge-mod"
}
}
// TODO: If neoforged is ever needed, should we use that, or call it a forge mod?
}
// Adds some dependencies that are in vanilla but not in core
if (p == project(":core")) {
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
// Set the OS lwjgl is using to the current os
// Set the OS lwjgl is using to the current os
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
dependencies {
// All of these dependencies are in Vanilla Minecraft, but we need to depend on them as we arent importing Minecraft in the core
// Imports most of lwjgl's libraries
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}")
dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core
// Imports most of lwjgl's libraries (well, only the ones that we need)
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions
// REMEMBER: Don't shadow stuff here, these are just the libs that are included in Minecraft so that the core can use them
// REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use
implementation "org.lwjgl:lwjgl"
implementation "org.lwjgl:lwjgl-assimp"
implementation "org.lwjgl:lwjgl-glfw"
// OpenGL is removed since DH now handles rendering in the "Common" project
// so we can use OpenGL for old MC versions and Blaze3D (IE Vulkan) for newer ones
// implementation "org.lwjgl:lwjgl-openal"
// implementation "org.lwjgl:lwjgl-opengl"
implementation "org.lwjgl:lwjgl-openal"
implementation "org.lwjgl:lwjgl-opengl"
implementation "org.lwjgl:lwjgl-stb"
implementation "org.lwjgl:lwjgl-tinyfd"
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
// runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
// runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives"
implementation "org.joml:joml:${rootProject.joml_version}"
@@ -662,6 +699,14 @@ allprojects { p ->
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
into(file(p.file("build/resources/main")))
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
// Move the fabricLike mixin to its different places for each subproject
if (findProject(":fabricLike")) {
from project(":fabricLike").file("src/main/resources/DistantHorizons.fabricLike.mixins.json")
into(file(p.file("build/resources/main")))
rename "DistantHorizons.fabricLike.mixins.json", "DistantHorizons." + p.name + ".fabricLike.mixins.json"
}
}
task copyCoreResources(type: Copy) {
@@ -674,6 +719,7 @@ allprojects { p ->
options.release = rootProject.java_version as Integer
} else {
options.release = 8; // Core & Api should use Java 8 no matter what
//options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled
}
options.encoding = "UTF-8"
}
@@ -1,7 +1,6 @@
package com.seibel.distanthorizons.common;
import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
import com.seibel.distanthorizons.common.commands.CommandInitializer;
@@ -19,10 +18,6 @@ import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.NativeDialogUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
@@ -50,7 +45,6 @@ public abstract class AbstractModInitializer
//==================//
// abstract methods //
//==================//
//region
protected abstract void createInitialSharedBindings();
protected abstract void createInitialClientBindings();
@@ -64,14 +58,11 @@ public abstract class AbstractModInitializer
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
protected abstract void runDelayedSetup();
//endregion
//===================//
// initialize events //
//===================//
//region
public void onInitializeClient()
{
@@ -102,7 +93,6 @@ public abstract class AbstractModInitializer
#endif
this.subscribeClientStartedEvent(this::postInit);
this.subscribeClientStartedEvent(this::postClientInit);
}
public void onInitializeServer()
@@ -142,14 +132,11 @@ public abstract class AbstractModInitializer
});
}
//endregion
//===========================//
// inner initializer methods //
//===========================//
//region
private void startup()
{
@@ -222,16 +209,11 @@ public abstract class AbstractModInitializer
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
}
private void postClientInit() { DependencySetup.setRenderingApiBindings(); }
//endregion
//==================================//
// mod partial compatibility checks //
//==================================//
//region
/**
* Some mods will work with a few tweaks
@@ -249,7 +231,6 @@ public abstract class AbstractModInitializer
// Alex's caves
//region
if (modChecker.isModLoaded("alexscaves"))
{
// There've been a few reports about this mod breaking DH at a few different points in time
@@ -266,10 +247,8 @@ public abstract class AbstractModInitializer
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly.");
}
//endregion
// William Wythers' Overhauled Overworld (WWOO)
//region
if (modChecker.isModLoaded("wwoo"))
{
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO
@@ -290,11 +269,8 @@ public abstract class AbstractModInitializer
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
}
//endregion
// Chunky //
//region
// Chunky
boolean chunkyPresent = false;
try
{
@@ -324,56 +300,17 @@ public abstract class AbstractModInitializer
LOGGER.warn(startingString + "[Chunky] "+ chunkyWarning);
}
//endregion
// iris //
//region
IIrisAccessor iris = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
if (iris != null)
{
// get the currently selected rendering API
EDhApiRenderApi renderApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderApi == EDhApiRenderApi.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderApi = versionConstants.getDefaultRenderingApi();
}
// Iris only supports nataive OpenGL
if (renderApi != EDhApiRenderApi.OPEN_GL)
{
String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+EDhApiRenderApi.BLAZE_3D+"] rendering API, please change it to ["+EDhApiRenderApi.OPEN_GL+"] in DH's config file.";
LOGGER.fatal(irisUnsupportedMessage);
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, irisUnsupportedMessage, "ok", "error");
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
String errorMessage = "loading Distant Horizons. "+irisUnsupportedMessage;
String exceptionError = "Distant Horizons conditional mod config Exception";
mc.crashMinecraft(errorMessage, new Exception(exceptionError));
}
}
//endregion
}
//endregion
//================//
// helper classes //
//================//
//region
public interface IEventProxy
{
void registerEvents();
}
//endregion
}
@@ -1,88 +0,0 @@
package com.seibel.distanthorizons.common.commonMixins;
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
import java.util.ArrayList;
public class DhUpdateScreenBase
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final Minecraft MC = Minecraft.getInstance();
public static void tryShowUpdateScreenAndRunAutoUpdateStartup(Runnable runnable)
{
// always needs to be called, otherwise auto update setup won't be completed
boolean newUpdateAvailable = SelfUpdater.onStart();
if (!newUpdateAvailable)
{
return;
}
if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
{
LOGGER.info("Auto update disabled, ignoring new version...");
return;
}
runnable = () ->
{
String versionId;
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
if (updateBranch == EDhApiUpdateBranch.STABLE)
{
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
}
else
{
ArrayList<com.electronwill.nightconfig.core.Config> pipelines = GitlabGetter.INSTANCE.projectPipelines;
if (pipelines != null
&& pipelines.size() > 0)
{
versionId = pipelines.get(0).get("sha");
}
else
{
versionId = null;
}
}
if (versionId == null)
{
LOGGER.info("Unable to find new DH update for the ["+updateBranch+"] branch. Assuming DH is up to date...");
return;
}
try
{
MC.setScreen(new UpdateModScreen(
new TitleScreen(false),
versionId
));
}
catch (Exception e)
{
// info instead of error since this can be ignored and probably just means
// there isn't a new DH version available
LOGGER.info("Unable to show DH update screen, reason: ["+e.getMessage()+"].");
}
};
runnable.run();
}
}
@@ -4,7 +4,6 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -14,10 +13,8 @@ public class MixinChunkMapCommon
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
{
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
// is this position already being updated?
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(levelWrapper, chunk.getPos().x, chunk.getPos().z))
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(chunk.getPos().x, chunk.getPos().z))
{
return;
}
@@ -32,6 +29,10 @@ public class MixinChunkMapCommon
return;
}
// TODO are the following validations necessary since we are checking above if
// the callback return value should state if the chunk was actually saved or not?
// Do we trust it to always be correct?
// corrupt/incomplete chunk validation //
@@ -76,8 +77,8 @@ public class MixinChunkMapCommon
// submit the update event
ServerApi.INSTANCE.serverChunkSaveEvent(
new ChunkWrapper(chunk, levelWrapper),
levelWrapper
new ChunkWrapper(chunk, ServerLevelWrapper.getWrapper(level)),
ServerLevelWrapper.getWrapper(level)
);
}
@@ -1,330 +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.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDebugWireframeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import net.minecraft.resources.Identifier;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Handles rendering the wireframe particles
* that are used for seeing what the system's doing.
*/
public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
public static BlazeDebugWireframeRenderer INSTANCE = new BlazeDebugWireframeRenderer();
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
//endregion
};
private static final int[] BOX_OUTLINE_INDICES = {
//region
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
//endregion
};
// rendering setup
private boolean init = false;
private RenderPipeline pipeline;
private GpuBuffer boxVertexBuffer;
private GpuBuffer boxIndexBuffer;
private GpuBuffer uniformBuffer;
//=============//
// constructor //
//=============//
//region
public BlazeDebugWireframeRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.createPipelines();
this.createBuffers();
}
private void createPipelines()
{
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.build();
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(PolygonMode.WIREFRAME);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:debug_wireframe_renderer"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "debug/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "debug/blaze/frag"));
pipelineBuilder.withUniform("uniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.DEBUG_LINES);
}
this.pipeline = pipelineBuilder.build();
}
private void createBuffers()
{
GpuDevice GPU_DEVICE = RenderSystem.getDevice();
CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
// box vertices
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
MemoryUtil.memFree(boxVerticesBuffer);
// upload vertex data
{
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = BOX_VERTICES.length * Float.BYTES;
this.boxVertexBuffer = GPU_DEVICE.createBuffer(() -> "distantHorizons:McDebugWireframeBox", usage, size);
{
int length = BOX_VERTICES.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxVertexBuffer, /*offset*/ 0, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(BOX_VERTICES);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
}
// box vertex indexes
{
ByteBuffer buffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
buffer.rewind();
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_INDEX
| GpuBuffer.USAGE_UNIFORM;
this.boxIndexBuffer = GPU_DEVICE.createBuffer(() -> "DH Debug Index Buffer", usage, buffer.capacity());
int offset = 0;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxIndexBuffer, offset, buffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
}
//endregion
//===========//
// rendering //
//===========//
//region
@Override
public void render(Box box)
{
this.init();
if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
{
return;
}
// shouldn't happen, but just in case
if (box == null)
{
return;
}
// delayed getters since this class may be initialized before
// the GPU device has been set
GpuDevice gpuDevice = RenderSystem.getDevice();
CommandEncoder commandEncoder = gpuDevice.createCommandEncoder();
// uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putMat4f() // uTransform
.putVec4() // uColor
.get();
// create data //
Vec3d camPos = MC_RENDER.getCameraExactPosition();
Vec3f camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
Mat4f boxTransform = Mat4f.createTranslateMatrix(
box.minPos.x - camPosFloatThisFrame.x,
box.minPos.y - camPosFloatThisFrame.y,
box.minPos.z - camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(
box.maxPos.x - box.minPos.x,
box.maxPos.y - box.minPos.y,
box.maxPos.z - box.minPos.z));
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putMat4f(transformMatrix.createJomlMatrix()) // uTransform
.putVec4(
box.color.getRed() / 255.0f,
box.color.getGreen() / 255.0f,
box.color.getBlue() / 255.0f,
box.color.getAlpha() / 255.0f) // uColor
.get()
;
this.uniformBuffer = BlazeUniformUtil.createBuffer("uniformBlock", uniformBufferSize, this.uniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.uniformBuffer, 0, uniformBufferSize);
commandEncoder.writeToBuffer(bufferSlice, buffer);
}
// render //
try (RenderPass renderPass = commandEncoder.createRenderPass(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
// Bind instance data //
renderPass.setUniform("uniformBlock", this.uniformBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.setIndexBuffer(this.boxIndexBuffer, VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, this.boxVertexBuffer);
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/BOX_OUTLINE_INDICES.length,
/*instanceCount*/1);
}
}
private String getRenderPassName() { return "distantHorizons:McDebugRenderer"; }
//endregion
}
#endif
@@ -1,630 +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.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhGenericObjectRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderCleanupEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.resources.Identifier;
import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.concurrent.ConcurrentHashMap;
/**
* Handles rendering generic groups of {@link DhApiRenderableBox}.
*
* @see IDhApiCustomRenderRegister
* @see DhApiRenderableBox
*/
public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
/**
* Can be used to troubleshoot the renderer.
* If enabled several debug objects will render around (0,150,0).
*/
public static final boolean RENDER_DEBUG_OBJECTS = false;
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
// rendering setup
private boolean init = false;
private VertexFormat vertexFormat;
private RenderPipeline opaquePipeline;
private RenderPipeline transparentPipeline;
private GpuBuffer vertUniformBuffer;
//=============//
// constructor //
//=============//
//region
public BlazeDhGenericObjectRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
.add("aColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
.add("aMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
.build();
this.createPipelines();
if (RENDER_DEBUG_OBJECTS)
{
this.addGenericDebugObjects();
}
}
private void createPipelines()
{
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(true);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:generic"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/blaze/frag"));
pipelineBuilder.withSampler("uLightMap");
pipelineBuilder.withUniform("vertUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withVertexFormat(this.vertexFormat, VertexFormat.Mode.TRIANGLES);
}
// opaque
{
pipelineBuilder.withoutBlend();
this.opaquePipeline = pipelineBuilder.build();
}
// transparent
{
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
this.transparentPipeline = pipelineBuilder.build();
}
}
private void addGenericDebugObjects()
{
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
// single giant box
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":CyanChunkBox",
new DhApiRenderableBox(
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
EDhApiBlockMaterial.WATER)
);
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleGiantBoxGroup);
// single slender box
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":GreenBeacon",
new DhApiRenderableBox(
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
EDhApiBlockMaterial.ILLUMINATED)
);
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleTallBoxGroup);
// absolute box group
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
for (int i = 0; i < 18; i++)
{
absBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
EDhApiBlockMaterial.LAVA
)
);
}
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
this.add(absolutePosBoxGroup);
// relative box group
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
for (int i = 0; i < 8; i+=2)
{
relBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
EDhApiBlockMaterial.METAL
)
);
}
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MovingMagentaGroup",
new DhApiVec3d(24, 140, 24),
relBoxList);
relativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
pos.x += event.partialTicks / 2;
pos.x %= 32;
relativePosBoxGroup.setOriginBlockPos(pos);
});
this.add(relativePosBoxGroup);
// massive relative box group
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
for (int x = 0; x < 50*2; x+=2)
{
for (int z = 0; z < 50*2; z+=2)
{
massRelBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
EDhApiBlockMaterial.TERRACOTTA
)
);
}
}
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MassRedGroup",
new DhApiVec3d(-25, 140, 0),
massRelBoxList);
massRelativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
blockPos.y += event.partialTicks / 4;
if (blockPos.y > 150f)
{
blockPos.y = 140f;
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
massRelativePosBoxGroup.triggerBoxChange();
}
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
});
this.add(massRelativePosBoxGroup);
}
//endregion
//==============//
// registration //
//==============//
//region
@Override
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
{
if (!(iBoxGroup instanceof RenderableBoxGroup))
{
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
}
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
long id = boxGroup.getId();
if (this.boxGroupById.containsKey(id))
{
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
}
this.boxGroupById.put(id, boxGroup);
}
@Override
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
public void clear() { this.boxGroupById.clear(); }
//endregion
//===========//
// rendering //
//===========//
//region
/**
* @param renderingWithSsao
* if true that means this render call is happening before the SSAO pass
* and any objects rendered in this pass will have SSAO applied to them.
*/
@Override
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
{
//==============//
// render setup //
//==============//
//#region
profiler.push("setup");
this.init();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
Vec3d camPos = MC_RENDER.getCameraExactPosition();
//#endregion
if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
{
return;
}
//===========//
// rendering //
//===========//
//#region
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case
if (boxGroup == null)
{
continue;
}
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != IDhGenericObjectVertexBufferContainer.EState.RENDER)
{
continue;
}
}
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
// uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putIVec3() // uOffsetChunk
.putVec3() // uOffsetSubChunk
.putIVec3() // uCameraPosChunk
.putVec3() // uCameraPosSubChunk
.putVec3() // aTranslateChunk
.putVec3() // aTranslateSubChunk
.putMat4f() // uProjectionMvm
.putInt() // uSkyLight
.putInt() // uBlockLight
.putFloat() // uNorthShading
.putFloat() // uSouthShading
.putFloat() // uEastShading
.putFloat() // uWestShading
.putFloat() // uTopShading
.putFloat() // uBottomShading
.get();
// create data //
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putIVec3(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
) // uOffsetSubChunk
.putIVec3(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
) // uCameraPosChunk
.putVec3(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
) // uCameraPosSubChunk
.putMat4f(projectionMvmMatrix.createJomlMatrix()) // uProjectionMvm
.putInt(boxGroup.getSkyLight()) // uSkyLight
.putInt(boxGroup.getBlockLight()) // uBlockLight
.putFloat(shading.north)
.putFloat(shading.south)
.putFloat(shading.east)
.putFloat(shading.west)
.putFloat(shading.top)
.putFloat(shading.bottom)
.get()
;
this.vertUniformBuffer = BlazeUniformUtil.createBuffer("vertUniformBlock", uniformBufferSize, this.vertUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
// render //
profiler.popPush("rendering");
profiler.push(boxGroup.getResourceLocationNamespace());
profiler.push(boxGroup.getResourceLocationPath());
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
this.renderBoxGroupInstanced(renderPass, renderEventParam, boxGroup, camPos, profiler);
}
profiler.pop(); // resource path
profiler.pop(); // resource namespace
boxGroup.postRender(renderEventParam);
}
//#endregion
//==========//
// clean up //
//==========//
//region
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
profiler.pop();
//endregion
}
private String getRenderPassName() { return "distantHorizons:McGenericObjectRenderer"; }
//endregion
//=====================//
// instanced rendering //
//=====================//
//region
private void renderBoxGroupInstanced(
RenderPass renderPass, RenderParams renderEventParam,
RenderableBoxGroup boxGroup, Vec3d camPos,
IProfilerWrapper profiler)
{
// update instance data //
profiler.push("vertex setup");
BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer;
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
// Bind instance data //
profiler.popPush("binding");
renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer);
// set pipeline
renderPass.setPipeline(this.opaquePipeline); // TODO
renderPass.setIndexBuffer(container.indexGpuBuffer, VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, container.vboGpuBuffer);
// Draw instanced
profiler.popPush("render");
if (container.uploadedBoxCount > 0)
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/container.uploadedBoxCount * 24, // TODO?
/*instanceCount*/1);
}
profiler.pop();
}
//endregion
//=========//
// F3 menu //
//=========//
//region
public String getVboRenderDebugMenuString()
{
// get counts
int totalGroupCount = this.boxGroupById.size();
int totalBoxCount = 0;
int activeGroupCount = 0;
int activeBoxCount = 0;
for (long key : this.boxGroupById.keySet())
{
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
if (renderGroup.active)
{
activeGroupCount++;
activeBoxCount += renderGroup.size();
}
totalBoxCount += renderGroup.size();
}
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
}
//endregion
}
#endif
@@ -1,94 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhMetaRenderer {}
#else
import com.mojang.blaze3d.textures.GpuTexture;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import net.minecraft.client.Minecraft;
public class BlazeDhMetaRenderer implements IDhMetaRenderer
{
public static final BlazeDhMetaRenderer INSTANCE = new BlazeDhMetaRenderer();
private BlazeDhApplyRenderer applyRenderer;
public final BlazeTextureWrapper dhDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhDepthTexture");
public final BlazeTextureWrapper dhColorTextureWrapper = BlazeTextureWrapper.createColor("DhColorTexture");
//=============//
// constructor //
//=============//
//region
private BlazeDhMetaRenderer()
{
this.applyRenderer = new BlazeDhApplyRenderer(
"dh_apply_to_mc",
null,
"apply/blaze/vert", "apply/blaze/frag"
);
}
//endregion
//=================//
// pre/post render //
//=================//
//region
@Override
public void runRenderPassSetup(RenderParams renderParams)
{
// textures
this.dhDepthTextureWrapper.tryCreateOrResize();
this.dhColorTextureWrapper.tryCreateOrResize();
}
@Override
public void runRenderPassCleanup(RenderParams renderParams) {}
@Override
public void applyToMcTexture(RenderParams renderParams)
{
GpuTexture mcColorTexture = Minecraft.getInstance().getMainRenderTarget().getColorTexture();
this.applyRenderer.render(this.dhColorTextureWrapper.texture, this.dhDepthTextureWrapper.texture, mcColorTexture);
}
//endregion
//================//
// clear textures //
//================//
//region
@Override
public void clearDhDepthAndColorTextures(RenderParams renderParams)
{
// TODO use for clear color
//IMinecraftRenderWrapper r;
//r.getSkyColor()
this.dhDepthTextureWrapper.clearDepth(1.0f);
this.dhColorTextureWrapper.clearColor(ColorUtil.argbToInt(1, 1, 1, 1));
}
//endregion
}
#endif
@@ -1,71 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhRenderApiDefinition {}
#else
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFarFadeRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFogRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhSsaoRenderer;
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeVanillaFadeRenderer;
import com.seibel.distanthorizons.common.render.blaze.test.BlazeDhTestTriangleRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.*;
public class BlazeDhRenderApiDefinition extends AbstractDhRenderApiDefinition
{
//=========//
// getters //
//=========//
//region
public String getApiName() { return "Blaze3D"; }
//endregion
//============//
// singletons //
//============//
//region
@Override public IDhMetaRenderer getMetaRenderer() { return BlazeDhMetaRenderer.INSTANCE; }
@Override public IDhTerrainRenderer getTerrainRenderer() { return BlazeDhTerrainRenderer.INSTANCE; }
@Override public IDhSsaoRenderer getSsaoRenderer() { return BlazeDhSsaoRenderer.INSTANCE; }
@Override public IDhFogRenderer getFogRenderer() { return BlazeDhFogRenderer.INSTANCE; }
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return BlazeDhFarFadeRenderer.INSTANCE; }
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return BlazeDebugWireframeRenderer.INSTANCE; }
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return BlazeVanillaFadeRenderer.INSTANCE; }
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return BlazeDhTestTriangleRenderer.INSTANCE; }
//endregion
//===========//
// factories //
//===========//
//region
@Override public IDhGenericRenderer createGenericRenderer() { return new BlazeDhGenericObjectRenderer(); }
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new BlazeVertexBufferWrapper(name); }
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new BlazeLodUniformBufferWrapper(); }
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new BlazeGenericObjectVertexContainer(); }
//endregion
}
#endif
@@ -1,394 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze;
#if MC_VER <= MC_1_21_10
public class BlazeDhTerrainRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GlQuadElementBuffer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.resources.Identifier;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/** Renders rendering DH's LOD terrain. */
public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhTerrainRenderer INSTANCE = new BlazeDhTerrainRenderer();
private RenderPipeline opaquePipeline;
private RenderPipeline transparentPipeline;
private boolean init = false;
private GpuBuffer indexBuffer;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vertSharedUniformBuffer;
//=============//
// constructor //
//=============//
//region
private BlazeDhTerrainRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true; // todo only set when succeeded (in case of exception)
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SHORT_XYZ_POS)
.add("meta", BlazeDhVertexFormatUtil.META)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
.add("irisMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
.add("irisNormal", BlazeDhVertexFormatUtil.IRIS_NORMAL)
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD) // padding is to make sure the format is a multiple of 4
.build();
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(true);
pipelineBuilder.withDepthWrite(true);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:lod_render"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "lod/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "lod/blaze/frag"));
pipelineBuilder.withSampler("uLightMap");
pipelineBuilder.withUniform("vertUniqueUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withUniform("vertSharedUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.TRIANGLES);
}
// opaque
{
pipelineBuilder.withoutBlend();
this.opaquePipeline = pipelineBuilder.build();
}
// transparent
{
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
this.transparentPipeline = pipelineBuilder.build();
}
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(
RenderParams renderEventParam,
boolean opaquePass,
SortedArraySet<LodBufferContainer> bufferContainers,
IProfilerWrapper profiler)
{
this.tryInit();
profiler.push("vert unique uniforms");
{
// create data //
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
bufferContainer.uniformContainer.tryUpload();
}
}
profiler.popPush("vert share uniforms");
{
Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
combinedMatrix.multiply(renderEventParam.dhModelViewMatrix);
float earthCurveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
if (earthCurveRatio < -1.0f || earthCurveRatio > 1.0f)
{
earthCurveRatio = /*6371KM*/ 6371000.0f / earthCurveRatio;
}
else
{
// disable curvature if the config value is between -1 and 1
earthCurveRatio = 0.0f;
}
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uIsWhiteWorld
.putFloat() // uWorldYOffset
.putFloat() // uMircoOffset
.putFloat() // uEarthRadius
.putVec3() // uCameraPos
.putMat4f() // uCombinedMatrix
.get();
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
Std140Builder.intoBuffer(buffer)
.putInt(0) // uIsWhiteWorld
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
.putFloat(earthCurveRatio) // uEarthRadius
.putVec3(
(float)renderEventParam.exactCameraPosition.x,
(float)renderEventParam.exactCameraPosition.y,
(float)renderEventParam.exactCameraPosition.z) // uCameraPos
.putMat4f(combinedMatrix.createJomlMatrix()) // uCombinedMatrix
.get();
this.vertSharedUniformBuffer = BlazeUniformUtil.createBuffer("vertSharedUniformBlock", uniformBufferSize, this.vertSharedUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertSharedUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
profiler.popPush("set frag uniforms");
{
int uniformBufferSize = new Std140SizeCalculator()
.putFloat() // uClipDistance
.putFloat() // uNoiseIntensity
.putInt() // uNoiseSteps
.putInt() // uNoiseDropoff
.putInt() // uDitherDhRendering
.putInt() // uNoiseEnabled
.get();
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
if (!Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
}
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putFloat(dhNearClipDistance) // uClipDistance
.putFloat(Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get()) // uNoiseIntensity
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get()) // uNoiseSteps
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get()) // uNoiseDropoff
.putInt(Config.Client.Advanced.Graphics.Quality.ditherDhFade.get() ? 1 : 0) // uDitherDhRendering
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get() ? 1 : 0) // uNoiseEnabled
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
// create index buffer
{
if (this.indexBuffer == null)
{
ByteBuffer buffer = MemoryUtil.memAlloc(LodQuadBuilder.getMaxBufferByteSize() * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT) * 6);
GlQuadElementBuffer.buildBuffer(LodQuadBuilder.getMaxBufferByteSize(), buffer, GL32.GL_UNSIGNED_INT);
// create buffer if needed
if (this.indexBuffer == null
|| this.indexBuffer.size() < buffer.capacity())
{
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_INDEX
| GpuBuffer.USAGE_UNIFORM;
this.indexBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, buffer.capacity());
}
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexBuffer, /*offset*/ 0, buffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
}
// render pass setup
{
profiler.popPush("setup");
// create a render pass
OptionalInt optionalClearColorAsInt = OptionalInt.empty();
OptionalDouble optionalDepthValueAsDouble = OptionalDouble.empty();
try(RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
optionalClearColorAsInt,
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, optionalDepthValueAsDouble)
)
{
// bind MC Lightmap
//renderPass.bindTexture("uLightMap", this.mcLightTextureViewWrapper.textureView, this.mcLightTextureViewWrapper.textureSampler);
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
// set pipeline
renderPass.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
renderPass.setIndexBuffer(this.indexBuffer, VertexFormat.IndexType.INT);
// shared uniforms
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setUniform("vertSharedUniformBlock", this.vertSharedUniformBuffer);
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
profiler.popPush("binding");
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
BlazeLodUniformBufferWrapper uniformWrapper = (BlazeLodUniformBufferWrapper)bufferContainer.uniformContainer;
boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugEnable.get();
if (columnBuilderDebugEnabled)
{
if (DhSectionPos.getDetailLevel(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugDetailLevel.get()
&& DhSectionPos.getX(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugXPos.get()
&& DhSectionPos.getZ(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugZPos.get())
{
int breakpoint = 0;
}
else
{
continue;
}
}
renderPass.setUniform("vertUniqueUniformBlock", uniformWrapper.gpuBuffer);
profiler.popPush("rendering");
// render each buffer
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vbos : bufferContainer.vbosTransparent;
for (int i = 0; i < bufferWrapperList.length; i++)
{
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
if (!bufferWrapper.uploaded
|| bufferWrapper.vertexCount == 0)
{
continue;
}
// fire render event
{
Vec3d camPos = renderEventParam.exactCameraPosition;
Vec3f modelPos = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
}
renderPass.setVertexBuffer(0, bufferWrapper.vboGpuBuffer); // vertex buffer can only be "0" lol
if (!bufferWrapper.vboGpuBuffer.isClosed())
{
renderPass.drawIndexed(
/*indexStart*/ 0,
/*firstIndex*/0,
/*indexCount*/bufferWrapper.indexCount,
/*instanceCount*/1);
}
}
}
}
}
profiler.pop();
}
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
private String getRenderPassName() { return "distantHorizons:McLodRenderer"; }
//endregion
}
#endif
@@ -1,268 +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.common.render.blaze.apply;
#if MC_VER <= MC_1_21_10
public class BlazeDhApplyRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.resources.Identifier;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Copies the given color texture
* where the depth (or another attribute) is valid.
* Often used to apply post processing effects or
* the DH texture to MC's color texture. <br><br>
*
* @see BlazeDhCopyRenderer
*/
public class BlazeDhApplyRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private RenderPipeline pipeline;
protected GpuBuffer vboGpuBuffer;
protected final String name;
protected final String identifierName;
public String getIdentifierName() { return this.identifierName; }
@Nullable
private final BlendFunction blendFunction;
private final String vertexShaderPath;
private final String fragmentShaderPath;
private final BlazeTextureViewWrapper sourceColorTextureViewWrapper = new BlazeTextureViewWrapper();
private final BlazeTextureViewWrapper sourceDepthTextureViewWrapper = new BlazeTextureViewWrapper();
private final BlazeTextureViewWrapper destinationColorTextureViewWrapper = new BlazeTextureViewWrapper();
/**
* Can be set for special application shaders that need
* extra information. <br><br>
*
* will be an empty array if unneeded
*/
private final String[] uniformNames;
/** will be an empty array if unneeded */
private final GpuBuffer[] uniformBuffers;
//=============//
// constructor //
//=============//
//region
public BlazeDhApplyRenderer(
String name,
@Nullable BlendFunction blendFunction,
String vertexShaderPath, String fragmentShaderPath
)
{
this(
name,
blendFunction,
vertexShaderPath, fragmentShaderPath,
new String[0] // no extra uniforms
);
}
public BlazeDhApplyRenderer(
String name,
@Nullable BlendFunction blendFunction,
String vertexShaderPath, String fragmentShaderPath,
String[] uniformNames
)
{
this.name = name;
this.identifierName = "distanthorizons:"+this.name;
this.blendFunction = blendFunction;
this.vertexShaderPath = vertexShaderPath;
this.fragmentShaderPath = fragmentShaderPath;
this.uniformNames = uniformNames;
this.uniformBuffers = new GpuBuffer[this.uniformNames.length];
}
private void tryInit(
GpuTexture sourceColorTexture,
GpuTexture sourceDepthTexture,
GpuTexture destinationColorTexture)
{
this.createPipeline();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData(this.name);
this.sourceColorTextureViewWrapper.tryWrap(sourceColorTexture);
this.sourceDepthTextureViewWrapper.tryWrap(sourceDepthTexture);
this.destinationColorTextureViewWrapper.tryWrap(destinationColorTexture);
}
private void createPipeline()
{
if (this.pipeline != null)
{
return;
}
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
if (this.blendFunction != null)
{
pipelineBuilder.withBlend(this.blendFunction);
}
else
{
pipelineBuilder.withoutBlend();
}
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse(this.identifierName)); // TODO will complain if capital letters are included
// TODO manually validate paths to confirm they exist and end with ".fsh" or ".vsh", MC silently fails if the files are missing/improperly named
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", this.vertexShaderPath));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", this.fragmentShaderPath));
for (int i = 0; i < this.uniformNames.length; i++)
{
String uniformName = this.uniformNames[i];
pipelineBuilder.withUniform(uniformName, UniformType.UNIFORM_BUFFER);
}
pipelineBuilder.withSampler("uSourceColorTexture");
pipelineBuilder.withSampler("uSourceDepthTexture");
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
}
//endregion
//========//
// render //
//========//
//region
public void setUniform(String uniformName, GpuBuffer uniformBuffer)
{
// the uniform array should be short enough (less than 10 items)
// where a sequential search should be plenty fast
for (int i = 0; i < this.uniformNames.length; i++)
{
String nameAtIndex = this.uniformNames[i];
if (nameAtIndex.equals(uniformName))
{
this.uniformBuffers[i] = uniformBuffer;
break;
}
}
}
public void render(
GpuTexture sourceColorTexture,
GpuTexture sourceDepthTexture,
GpuTexture destinationColorTexture)
{
this.tryInit(sourceColorTexture, sourceDepthTexture, destinationColorTexture);
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getIdentifierName,
this.destinationColorTextureViewWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
/*depthTexture*/ null,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uSourceColorTexture", this.sourceColorTextureViewWrapper.textureView, this.sourceColorTextureViewWrapper.textureSampler);
renderPass.bindTexture("uSourceDepthTexture", this.sourceDepthTextureViewWrapper.textureView, this.sourceDepthTextureViewWrapper.textureSampler);
for (int i = 0; i < this.uniformNames.length; i++)
{
String uniformName = this.uniformNames[i];
GpuBuffer uniformBuffer = this.uniformBuffers[i];
if (uniformBuffer == null)
{
throw new IllegalStateException("Missing uniform ["+uniformName+"], please set the uniform before rendering.");
}
renderPass.setUniform(uniformName, uniformBuffer);
}
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
// clear the uniforms after rendering
// so we can check if they're missing during next frame's rendering
if (ModInfo.IS_DEV_BUILD)
{
Arrays.fill(this.uniformBuffers, null);
}
}
//endregion
}
#endif
@@ -1,165 +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.common.render.blaze.apply;
#if MC_VER <= MC_1_21_10
public class BlazeDhCopyRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.resources.Identifier;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Blindly copies one texture into another.
*
* @see BlazeDhApplyRenderer
*/
public class BlazeDhCopyRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhCopyRenderer INSTANCE = new BlazeDhCopyRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer vboGpuBuffer;
//=============//
// constructor //
//=============//
//region
private BlazeDhCopyRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:copy_render"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "copy/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "copy/blaze/frag"));
pipelineBuilder.withSampler("uCopyTexture");
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McCopyRenderer");
}
//endregion
//========//
// render //
//========//
//region
public void render(
BlazeTextureWrapper sourceColorTextureWrapper,
BlazeTextureViewWrapper destinationColorTextureWrapper)
{
this.render(
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
destinationColorTextureWrapper.textureView);
}
public void render(
BlazeTextureWrapper sourceColorTextureWrapper,
BlazeTextureWrapper destinationColorTextureWrapper)
{
this.render(
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
destinationColorTextureWrapper.textureView);
}
private void render(
GpuTextureView sourceTextureView,
GpuSampler sourceTextureSampler,
GpuTextureView destinationTextureView)
{
this.tryInit();
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
destinationTextureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
/*depthTexture*/ null,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uCopyTexture", sourceTextureView, sourceTextureSampler);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McCopyRenderer"; }
//endregion
}
#endif
@@ -1,285 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.objects;
#if MC_VER <= MC_1_21_10
public class BlazeGenericObjectVertexContainer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.ColorUtil;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
/**
* For use by {@link RenderableBoxGroup}
*
* @see RenderableBoxGroup
*/
public class BlazeGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private static final int[] BOX_INDICES = {
//region
// min X, vertical face
2, 1, 0,
0, 3, 2,
// max X, vertical face
6, 5, 4,
4, 7, 6,
// min Z, vertical face
10, 9, 8,
8, 11, 10,
// max Z, vertical face
14, 13, 12,
12, 15, 14,
// min Y, horizontal face
18, 17, 16,
16, 19, 18,
// max Y, horizontal face
20, 21, 22,
22, 23, 20,
//endregion
};
public GpuBuffer vboGpuBuffer;
public GpuBuffer indexGpuBuffer;
private ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(0);
private ByteBuffer indexBuffer = ByteBuffer.allocateDirect(0);
public int uploadedBoxCount = 0;
private EState state = EState.NEW;
@Override
public IDhGenericObjectVertexBufferContainer.EState getState() { return this.state; }
@Override
public void setState(IDhGenericObjectVertexBufferContainer.EState state) { this.state = state; }
//===========================//
// render building/uploading //
//===========================//
//region
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
{
int boxCount = uploadBoxList.size();
if (boxCount == 0)
{
return; // TODO done just to fix a buffer empty crash
}
// recreate the data arrays if their size is different
if (this.uploadedBoxCount != boxCount)
{
this.uploadedBoxCount = boxCount;
int vertexBufferSize = this.vertexBufferSize();
this.vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize);
this.vertexBuffer.order(ByteOrder.nativeOrder());
int indexBufferSize = this.indexBufferSize();
this.indexBuffer = ByteBuffer.allocateDirect(indexBufferSize);
this.indexBuffer.order(ByteOrder.nativeOrder());
}
this.vertexBuffer.position(0);
this.indexBuffer.position(0);
for (int boxIndex = 0; boxIndex < boxCount; boxIndex++)
{
// index
int indexOffset = (boxIndex * 24 /*24 is the number of vertices in a box*/);
for (int i = 0; i < BOX_INDICES.length; i++)
{
this.indexBuffer.putInt(BOX_INDICES[i] + indexOffset);
}
// vertex
DhApiRenderableBox box = uploadBoxList.get(boxIndex);
final double[] boxVertices =
{
//region
// Pos x y z
// min X, vertical face
box.minPos.x, box.minPos.y, box.minPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
// max X, vertical face
box.minPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.minPos.x, box.minPos.y, box.maxPos.z,
// min Z, vertical face
box.minPos.x, box.minPos.y, box.maxPos.z,
box.minPos.x, box.minPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.maxPos.z,
// max Z, vertical face
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
// min Y, horizontal face
box.minPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.maxPos.z,
box.maxPos.x, box.minPos.y, box.minPos.z,
box.minPos.x, box.minPos.y, box.minPos.z,
// max Y, horizontal face
box.minPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.maxPos.z,
box.maxPos.x, box.maxPos.y, box.minPos.z,
box.minPos.x, box.maxPos.y, box.minPos.z,
//endregion
};
for (int vertexIndex = 0; vertexIndex < boxVertices.length; vertexIndex+=3)
{
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex]); // x
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+1]); // y
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+2]); // z
int color = ColorUtil.toColorInt(box.color);
byte r = (byte) ColorUtil.getRed(color);
byte g = (byte) ColorUtil.getGreen(color);
byte b = (byte) ColorUtil.getBlue(color);
byte a = (byte) ColorUtil.getAlpha(color);
this.vertexBuffer.put(r);
this.vertexBuffer.put(g);
this.vertexBuffer.put(b);
this.vertexBuffer.put(a);
this.vertexBuffer.put(box.material);
// TODO make sure this all is a multiple of 4 like LodQuadBuilder (might cause issues with AMD/Mac otherwise)
}
}
this.vertexBuffer.flip();
this.indexBuffer.flip();
this.state = BlazeGenericObjectVertexContainer.EState.READY_TO_UPLOAD;
}
private int vertexBufferSize()
{
int faceCount = this.uploadedBoxCount * 6;
int vertexCount = faceCount * 6;
int byteSize = vertexCount * 3 * Float.BYTES; // x,y,z
byteSize += vertexCount * 4; // r,g,b,a
byteSize += 1; // material
return byteSize;
}
private int indexBufferSize()
{
int quadCount = this.uploadedBoxCount * 36;
int byteSize = quadCount * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT) * 6;
return byteSize;
}
public void uploadDataToGpu()
{
// vertex
{
int totalVertexByteSize = this.vertexBufferSize();
if (this.vboGpuBuffer == null
|| this.vboGpuBuffer.size() < totalVertexByteSize)
{
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getVertexBufferName, usage, totalVertexByteSize);
}
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, totalVertexByteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.vertexBuffer);
}
// index
{
int totalVertexByteSize = this.indexBufferSize();
if (this.indexGpuBuffer == null
|| this.indexGpuBuffer.size() < totalVertexByteSize)
{
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_INDEX
| GpuBuffer.USAGE_UNIFORM;
this.indexGpuBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, totalVertexByteSize);
}
int offset = 0;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, offset, totalVertexByteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.indexBuffer);
}
this.state = EState.RENDER;
}
private String getVertexBufferName() { return "distantHorizons:GenericVertexBuffer"; }
private String getIndexBufferName() { return "distantHorizons:GenericIndexBuffer"; }
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread(() ->
{
if (this.vboGpuBuffer != null)
{
this.vboGpuBuffer.close();
}
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
});
}
//endregion
}
#endif
@@ -1,235 +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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhFarFadeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.Identifier;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Fades out DH's far clip plane
*/
public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhFarFadeRenderer INSTANCE = new BlazeDhFarFadeRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vboGpuBuffer;
public final BlazeTextureWrapper dhFadeColorTextureWrapper = BlazeTextureWrapper.createColor("DhFadeColorTexture");
public final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
//=============//
// constructor //
//=============//
//region
private BlazeDhFarFadeRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:far_fade"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/dh_fade"));
pipelineBuilder.withSampler("uMcColorTexture");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withSampler("uDhColorTexture");
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.dhFadeColorTextureWrapper.tryCreateOrResize();
this.mcColorTextureViewWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
{
int uniformBufferSize = new Std140SizeCalculator()
.putFloat() // uStartFadeBlockDistance
.putFloat() // uEndFadeBlockDistance
.putMat4f() // uDhInvMvmProj
.get();
// create data //
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
float fadeStartDistance = dhFarClipDistance * 0.5f;
float fadeEndDistance = dhFarClipDistance * 0.9f;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
Mat4f inverseDhMvmProjMatrix = new Mat4f(dhProjectionMatrix);
inverseDhMvmProjMatrix.multiply(dhModelViewMatrix);
inverseDhMvmProjMatrix.invert();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderFadeToTexture();
BlazeDhCopyRenderer.INSTANCE.render(this.dhFadeColorTextureWrapper, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
}
private void renderFadeToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.dhFadeColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
/*depthTexture*/ null,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
// MC texture
renderPass.bindTexture("uMcColorTexture", this.mcColorTextureViewWrapper.textureView, this.mcColorTextureViewWrapper.textureSampler);
// DH textures
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
//endregion
}
#endif
@@ -1,363 +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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhFogRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.platform.SourceFactor;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFogRenderer;
import net.minecraft.resources.Identifier;
import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Renders fog onto the LODs.
*/
public class BlazeDhFogRenderer implements IDhFogRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhFogRenderer INSTANCE = new BlazeDhFogRenderer();
private BlazeDhApplyRenderer applyRenderer;
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vboGpuBuffer;
public BlazeTextureWrapper fogColorTextureWrapper = BlazeTextureWrapper.createColor("DhFogColorTexture");
//=============//
// constructor //
//=============//
//region
private BlazeDhFogRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
this.applyRenderer = new BlazeDhApplyRenderer(
"fog_apply_to_dh",
new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA),
"apply/blaze/vert", "apply/blaze/frag"
);
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:fog_render"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "fog/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "fog/blaze/frag"));
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFogRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
this.fogColorTextureWrapper.tryCreateOrResize();
{
int uniformBufferSize = new Std140SizeCalculator()
// fog uniforms
.putVec4() // uFogColor
.putFloat() //uFogScale
.putFloat() //uFogVerticalScale
// only used for debugging
.putInt() //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
.putInt() //uFogFalloffType
// fog config
.putFloat() // uFarFogStart
.putFloat() // uFarFogLength
.putFloat() // uFarFogMin
.putFloat() // uFarFogRange
.putFloat() // uFarFogDensity
// height fog config
.putFloat() // uHeightFogStart
.putFloat() // uHeightFogLength
.putFloat() // uHeightFogMin
.putFloat() // uHeightFogRange
.putFloat() // uHeightFogDensity
// ??
.putInt() // uHeightFogEnabled
.putInt() // uHeightFogFalloffType
.putInt() // uHeightBasedOnCamera
.putFloat() // uHeightFogBaseHeight
.putInt() // uHeightFogAppliesUp
.putInt() // uHeightFogAppliesDown
.putInt() // uUseSphericalFog
.putInt() // uHeightFogMixingMode
.putFloat() // uCameraBlockYPos
.putMat4f() // uInvMvmProj
.get();
// create data //
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
Mat4f inverseMvmProjMatrix = new Mat4f(renderParams.dhMvmProjMatrix);
inverseMvmProjMatrix.invert();
if (renderParams.dhMvmProjMatrix == null)
{
return;
}
Color fogColor = this.getFogColor(renderParams.partialTicks);
// fog config
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
// override fog if underwater
if (MC_RENDER.isFogStateSpecial())
{
// hide everything behind fog
farFogStart = 0.0f;
farFogEnd = 0.0f;
}
// height config
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
// fog uniforms
.putVec4(
fogColor.getRed() / 255.0f,
fogColor.getGreen() / 255.0f,
fogColor.getBlue() / 255.0f,
fogColor.getAlpha() / 255.0f) // uFogColor
.putFloat(1.f / lodDrawDistance) //uFogScale
.putFloat(1.f / MC.getWrappedClientLevel().getMaxHeight()) //uFogVerticalScale
// only used for debugging
.putInt(0) //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
.putInt(Config.Client.Advanced.Graphics.Fog.farFogFalloff.get().value) //uFogFalloffType
// fog config
.putFloat(farFogStart) // uFarFogStart
.putFloat(farFogEnd - farFogStart) // uFarFogLength
.putFloat(farFogMin) // uFarFogMin
.putFloat(farFogMax - farFogMin) // uFarFogRange
.putFloat(farFogDensity) // uFarFogDensity
// height fog config
.putFloat(heightFogStart) // uHeightFogStart
.putFloat(heightFogEnd - heightFogStart) // uHeightFogLength
.putFloat(heightFogMin) // uHeightFogMin
.putFloat(heightFogMax - heightFogMin) // uHeightFogRange
.putFloat(heightFogDensity) // uHeightFogDensity
// ??
.putInt(heightFogEnabled ? 1 : 0) // uHeightFogEnabled
.putInt(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value) // uHeightFogFalloffType
.putInt(heightFogCameraDirection.basedOnCamera ? 1 : 0) // uHeightBasedOnCamera
.putFloat(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get()) // uHeightFogBaseHeight
.putInt(heightFogCameraDirection.fogAppliesUp ? 1 : 0) // uHeightFogAppliesUp
.putInt(heightFogCameraDirection.fogAppliesDown ? 1 : 0) // uHeightFogAppliesDown
.putInt(useSphericalFog ? 1 : 0) // uUseSphericalFog
.putInt(heightFogMixingMode.value) // uHeightFogMixingMode
.putFloat((float)MC_RENDER.getCameraExactPosition().y) // uCameraBlockYPos
.putMat4f(inverseMvmProjMatrix.createJomlMatrix()) // uInvMvmProj
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderFogToTexture();
this.applyRenderer.render(this.fogColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
}
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 void renderFogToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.fogColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
/*depthTexture*/ null,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFogRenderer"; }
//endregion
}
#endif
@@ -1,283 +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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeDhSsaoRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.BlendFunction;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.DestFactor;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.platform.SourceFactor;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhSsaoRenderer;
import net.minecraft.resources.Identifier;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/** Renders SSAO to the DH LODs. */
public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhSsaoRenderer INSTANCE = new BlazeDhSsaoRenderer();
private BlazeDhApplyRenderer applyRenderer;
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer applyFragUniformBuffer;
private GpuBuffer vboGpuBuffer;
public BlazeTextureWrapper ssaoColorTextureWrapper = BlazeTextureWrapper.createColor("DhSsaoTexture");
//=============//
// constructor //
//=============//
//region
private BlazeDhSsaoRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
this.applyRenderer = new BlazeDhApplyRenderer(
"ssao_apply_to_dh",
new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE),
"apply/blaze/vert", "ssao/blaze/apply",
/*uniforms*/ new String[] { "applyFragUniformBlock" }
);
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:ssao_render"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/blaze/frag"));
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McSsao");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.ssaoColorTextureWrapper.tryCreateOrResize();
// frag uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uSampleCount\
.putFloat() // uRadius
.putFloat() // uStrength
.putFloat() // uMinLight
.putFloat() // uBias
.putFloat() // uFadeDistanceInBlocks
.putMat4f() // uInvProj
.putMat4f() // uProj
.get();
// create data //
Mat4f projMatrix = new Mat4f(renderParams.dhProjectionMatrix);
Mat4f invertedProjMatrix = new Mat4f(renderParams.dhProjectionMatrix);
invertedProjMatrix.invert();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putInt(6) // uSampleCount
.putFloat(4.0f) // uRadius
.putFloat(0.2f) // uStrength
.putFloat(0.25f) // uMinLight
.putFloat(0.02f) // uBias
.putFloat(1_600.0f) // uFadeDistanceInBlocks
.putMat4f(invertedProjMatrix.createJomlMatrix())
.putMat4f(projMatrix.createJomlMatrix())
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
// apply frag uniforms
{
int uniformBufferSize = new Std140SizeCalculator()
.putVec2() // uViewSize
.putInt() // uBlurRadius
.putFloat() // uNearClipPlane
.putFloat() // uFarClipPlane
.get();
// create data //
float viewWidth = (float)MC_RENDER.getTargetFramebufferViewportWidth();
float viewHeight = (float)MC_RENDER.getTargetFramebufferViewportHeight();
float nearClipPlane = RenderUtil.getNearClipPlaneInBlocks();
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putVec2(viewWidth, viewHeight) // uViewSize
.putInt(2) // uBlurRadius
.putFloat(nearClipPlane) // uNearClipPlane
.putFloat(farClipPlane) // uFarClipPlane
.get()
;
this.applyFragUniformBuffer = BlazeUniformUtil.createBuffer("applyFragUniformBlock", uniformBufferSize, this.applyFragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.applyFragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderSsaoToTexture();
this.applyRenderer.setUniform("applyFragUniformBlock", this.applyFragUniformBuffer);
this.applyRenderer.render(this.ssaoColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
}
private void renderSsaoToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.ssaoColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
/*depthTexture*/ null,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McSsaoRenderer"; }
//endregion
}
#endif
@@ -1,262 +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.common.render.blaze.postProcessing;
#if MC_VER <= MC_1_21_10
public class BlazeVanillaFadeRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.shaders.UniformType;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.Identifier;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Fades the vanilla chunks
* into DH's LODs.
*/
public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeVanillaFadeRenderer INSTANCE = new BlazeVanillaFadeRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuBuffer fragUniformBuffer;
private GpuBuffer vboGpuBuffer;
public final BlazeTextureWrapper fadeColorTextureWrapper = BlazeTextureWrapper.createColor("DhVanillaFadeTexture");
public final BlazeTextureViewWrapper mcDepthTextureWrapper = new BlazeTextureViewWrapper();
public final BlazeTextureViewWrapper mcColorTextureWrapper = new BlazeTextureViewWrapper();
//=============//
// constructor //
//=============//
//region
private BlazeVanillaFadeRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:mc_vanilla_fade_render"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/vanilla_fade"));
pipelineBuilder.withSampler("uMcDepthTexture");
pipelineBuilder.withSampler("uCombinedMcDhColorTexture");
pipelineBuilder.withSampler("uDhDepthTexture");
pipelineBuilder.withSampler("uDhColorTexture");
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
}
this.pipeline = pipelineBuilder.build();
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
{
return;
}
// textures
this.fadeColorTextureWrapper.tryCreateOrResize();
this.mcDepthTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getDepthTexture());
this.mcColorTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
{
int uniformBufferSize = new Std140SizeCalculator()
.putInt() // uOnlyRenderLods
.putFloat() // uStartFadeBlockDistance
.putFloat() // uEndFadeBlockDistance
.putFloat() // uMaxLevelHeight
.putMat4f() // uDhInvMvmProj
.putMat4f() // uMcInvMvmProj
.get();
// create data //
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
// measured in blocks
// these multipliers in James' tests should provide a fairly smooth transition
// without having underdraw issues
float fadeStartDistance = dhNearClipDistance * 1.5f;
float fadeEndDistance = dhNearClipDistance * 1.9f;
Mat4f inverseMcModelViewProjectionMatrix = new Mat4f(renderParams.mcProjectionMatrix);
inverseMcModelViewProjectionMatrix.multiply(renderParams.mcModelViewMatrix);
inverseMcModelViewProjectionMatrix.invert();
Mat4f inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
Mat4f inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
// upload data //
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
buffer.order(ByteOrder.nativeOrder());
buffer = Std140Builder.intoBuffer(buffer)
.putInt(Config.Client.Advanced.Debugging.lodOnlyMode.get() ? 1 : 0) // uOnlyRenderLods
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
.putFloat(renderParams.clientLevelWrapper.getMaxHeight()) // uMaxLevelHeight
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
.putMat4f(inverseMcMvmProjMatrix.createJomlMatrix()) // uMcInvMvmProj
.get()
;
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
this.renderFadeToTexture();
BlazeDhCopyRenderer.INSTANCE.render(this.fadeColorTextureWrapper, this.mcColorTextureWrapper);
}
private void renderFadeToTexture()
{
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.fadeColorTextureWrapper.textureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
/*depthTexture*/ null,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.bindTexture("uMcDepthTexture", this.mcDepthTextureWrapper.textureView, this.mcDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uCombinedMcDhColorTexture", this.mcColorTextureWrapper.textureView, this.mcColorTextureWrapper.textureSampler);
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
}
}
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
//endregion
}
#endif
@@ -1,192 +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.common.render.blaze.test;
#if MC_VER <= MC_1_21_10
public class BlazeDhTestTriangleRenderer {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.platform.PolygonMode;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.Identifier;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.OptionalDouble;
import java.util.OptionalInt;
/**
* Renders the OpenGL/Vulkan triangle
* to the center of the screen to confirm DH's
* apply shader is running correctly
*/
public class BlazeDhTestTriangleRenderer implements IDhTestTriangleRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static final BlazeDhTestTriangleRenderer INSTANCE = new BlazeDhTestTriangleRenderer();
private RenderPipeline pipeline;
private boolean init = false;
private GpuTextureView mcColorTextureView;
private GpuBuffer vboGpuBuffer;
//=============//
// constructor //
//=============//
//region
private BlazeDhTestTriangleRenderer() { }
private void tryInit()
{
if (this.init)
{
return;
}
this.init = true;
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.add("vColor", BlazeDhVertexFormatUtil.RGBA_FLOAT_COLOR)
.build();
//int breakpointOne = 0;
// needs to manually be set if the VertexFormatElement isn't registered
//this.vertexFormat.getOffsetsByElement()[this.posForm.id()] = 0;
//this.vertexFormat.getOffsetsByElement()[this.colForm.id()] = Float.BYTES * 2;
//
//int breakpointTwo = 0;
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
{
pipelineBuilder.withCull(false);
pipelineBuilder.withDepthWrite(false);
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
pipelineBuilder.withColorWrite(true);
pipelineBuilder.withoutBlend();
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:test_render"));
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "test/blaze/vert"));
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "test/blaze/frag"));
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.TRIANGLES);
}
this.pipeline = pipelineBuilder.build();
this.mcColorTextureView = GPU_DEVICE.createTextureView(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
this.uploadVertexData();
}
private void uploadVertexData()
{
// vertices for the OpenGL/Vulkan Triangle
float[] vertices = new float[]
{
// PosX,Y, ColorR,G,B,A
-0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
};
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = vertices.length * Float.BYTES;
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getRenderPassName, usage, size);
{
int offset = 0;
int length = vertices.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, offset, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
// Fill buffer with vertices.
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(vertices);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.tryInit();
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName,
this.mcColorTextureView,
/*optionalClearColorAsInt*/ OptionalInt.empty(),
/*mcDepthTextureView*/ null,
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
{
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
renderPass.setPipeline(this.pipeline);
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 3);
}
}
private String getRenderPassName() { return "distantHorizons:DhTestRenderer"; }
//endregion
}
#endif
@@ -1,105 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazeDhVertexFormatUtil {}
#else
import com.mojang.blaze3d.vertex.VertexFormatElement;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
/**
* @see LodQuadBuilder
*/
public class BlazeDhVertexFormatUtil
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static final VertexFormatElement SCREEN_POS;
public static final VertexFormatElement RGBA_FLOAT_COLOR;
public static final VertexFormatElement SHORT_XYZ_POS;
public static final VertexFormatElement BYTE_PAD;
/** contains light and micro-offset */
public static final VertexFormatElement META;
public static final VertexFormatElement RGBA_UBYTE_COLOR;
public static final VertexFormatElement IRIS_MATERIAL;
public static final VertexFormatElement IRIS_NORMAL;
public static final VertexFormatElement FLOAT_XYZ_POS;
static
{
EDhApiRenderApi renderingApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderingApi == EDhApiRenderApi.AUTO)
{
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
renderingApi = versionConstants.getDefaultRenderingApi();
}
boolean register = (renderingApi == EDhApiRenderApi.BLAZE_3D);
if (register)
{
LOGGER.debug("Attempting to register ["+VertexFormatElement.class.getSimpleName()+"]...");
try
{
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 2);
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.COLOR, /*count*/ 4);
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, VertexFormatElement.Usage.COLOR, /*count*/ 4);
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
}
catch (Exception e)
{
String message = "Unable to register one or more ["+VertexFormatElement.class.getSimpleName()+"] this is likely caused by another mod registering their own custom ["+VertexFormatElement.class.getSimpleName()+"]'s. This should be fixed in the next major Minecraft version.";
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
mc.crashMinecraft(message, new Exception(message, e));
// here to make the compiler happy, the process should shut down before this
throw new RuntimeException(e);
}
LOGGER.debug("Successfully registered ["+VertexFormatElement.class.getSimpleName()+"].");
}
else
{
SCREEN_POS = null;
RGBA_FLOAT_COLOR = null;
SHORT_XYZ_POS = null;
BYTE_PAD = null;
META = null;
RGBA_UBYTE_COLOR = null;
IRIS_MATERIAL = null;
IRIS_NORMAL = null;
FLOAT_XYZ_POS = null;
}
}
}
#endif
@@ -1,81 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazePostProcessUtil {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.function.Supplier;
/** Contains code that's used by all post-processing effects. */
public class BlazePostProcessUtil
{
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
// vertices for a full-screen quad
private static final float[] VERTICES = new float[]
{
// PosX,Y,
-1f, -1f,
1f, -1f,
1f, 1f,
-1f, 1f,
};
//=========//
// methods //
//=========//
//region
public static GpuBuffer createAndUploadScreenVertexData(String name)
{
Supplier<String> labelSupplier = () -> "distantHorizons:"+name;
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int size = VERTICES.length * Float.BYTES;
GpuBuffer vboGpuBuffer = GPU_DEVICE.createBuffer(labelSupplier, usage, size);
{
int length = VERTICES.length * Float.BYTES;
GpuBufferSlice bufferSlice = new GpuBufferSlice(vboGpuBuffer, /*offset*/ 0, length);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VERTICES.length * Float.BYTES);
// Fill buffer with vertices.
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.asFloatBuffer().put(VERTICES);
byteBuffer.rewind();
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
}
return vboGpuBuffer;
}
public static VertexFormat createVertexFormat()
{
VertexFormat vertexFormat = VertexFormat.builder()
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
.build();
return vertexFormat;
}
//endregion
}
#endif
@@ -1,38 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.util;
#if MC_VER <= MC_1_21_10
public class BlazeUniformUtil {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
public class BlazeUniformUtil
{
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public static GpuBuffer createBuffer(String uniformName, int size, GpuBuffer vboGpuBuffer)
{
// create VBO if needed
if (vboGpuBuffer == null
|| vboGpuBuffer.size() < size)
{
// GpuBuffer.USAGE_UNIFORM = 128
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_UNIFORM;
vboGpuBuffer = GPU_DEVICE.createBuffer(() -> uniformName, usage, size);
}
return vboGpuBuffer;
}
}
#endif
@@ -1,90 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.buffer;
#if MC_VER <= MC_1_21_10
public class BlazeVertexBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import java.nio.ByteBuffer;
public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
{
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public final String name;
public String getName() { return this.name; }
public GpuBuffer vboGpuBuffer = null;
public int vertexCount = -1;
public int indexCount = -1;
public boolean uploaded = false;
//=============//
// constructor //
//=============//
//region
public BlazeVertexBufferWrapper(String name) { this.name = name; }
//endregion
//========//
// upload //
//========//
//region
@Override
public void upload(ByteBuffer buffer, int vertexCount)
{
this.vertexCount = vertexCount;
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
this.indexCount = (int)(vertexCount * 1.5);
this.uploaded = true;
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int byteSize = (buffer.limit() - buffer.position());
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, byteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
if (this.vboGpuBuffer != null)
{
this.vboGpuBuffer.close();
}
}
//endregion
}
#endif
@@ -1,72 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
#if MC_VER <= MC_1_21_10
public class BlazeTextureViewWrapper {}
#else
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import java.util.OptionalDouble;
public class BlazeTextureViewWrapper
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public GpuTextureView textureView = null;
public GpuSampler textureSampler = null;
//=======//
// setup //
//=======//
//region
/** does nothing if the texture is already wrapped */
public void tryWrap(GpuTexture texture)
{
this.tryRecreateTextureView(texture);
this.tryCreateSampler();
}
private void tryRecreateTextureView(GpuTexture texture)
{
if (this.textureView == null
|| this.textureView.texture() != texture)
{
if (this.textureView != null)
{
this.textureView.close();
}
this.textureView = GPU_DEVICE.createTextureView(texture);
}
}
private void tryCreateSampler()
{
if (this.textureSampler == null)
{
this.textureSampler = GPU_DEVICE.createSampler(
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
1, // maxAnisotropy
OptionalDouble.empty() // maxLod
);
}
}
//endregion
}
#endif
@@ -1,167 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
#if MC_VER <= MC_1_21_10
public class BlazeTextureWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.*;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import java.util.OptionalDouble;
public class BlazeTextureWrapper
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
public final String name;
public final TextureFormat textureFormat;
public GpuTexture texture = null;
public GpuTextureView textureView = null;
public GpuSampler textureSampler = null;
private int width = -1;
private int height = -1;
//==============//
// constructors //
//==============//
//region
public static BlazeTextureWrapper createDepth(String name) { return new BlazeTextureWrapper(name, TextureFormat.DEPTH32); }
public static BlazeTextureWrapper createColor(String name) { return new BlazeTextureWrapper(name, TextureFormat.RGBA8); }
private BlazeTextureWrapper(String name, TextureFormat textureFormat)
{
this.name = name;
this.textureFormat = textureFormat;
}
//endregion
//=========//
// getters //
//=========//
//region
public boolean isEmpty() { return this.texture == null; }
/** @return -1 if the texture is null */
public int getWidth() { return this.width; }
/** @return -1 if the texture is null */
public int getHeight() { return this.height; }
//endregion
//=======//
// setup //
//=======//
//region
/** does nothing if the texture is already created and the correct size */
public void tryCreateOrResize()
{
this.tryCreateTexture();
this.tryCreateSampler();
}
private void tryCreateTexture()
{
int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth();
int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.texture == null
|| this.width != viewWidth
|| this.height != viewHeight)
{
if (this.texture != null)
{
this.texture.close();
this.textureView.close();
}
this.width = viewWidth;
this.height = viewHeight;
int usage = GpuBuffer.USAGE_HINT_CLIENT_STORAGE
| GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_UNIFORM;
this.texture = GPU_DEVICE.createTexture(this.name,
usage,
this.textureFormat,
viewWidth, viewHeight,
/*depthOrLayers*/ 1, /*mipLevels*/ 1
);
this.textureView = GPU_DEVICE.createTextureView(this.texture);
}
}
private void tryCreateSampler()
{
if (this.textureSampler == null)
{
this.textureSampler = GPU_DEVICE.createSampler(
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
1, // maxAnisotropy
OptionalDouble.empty() // maxLod
);
}
}
//endregion
//==========//
// clearing //
//==========//
//region
/**
* Will throw an exception if not a color texture.
* @see ColorUtil#argbToInt
*/
public void clearColor(int clearArgbColor)
{
if (this.texture != null)
{
COMMAND_ENCODER.clearColorTexture(this.texture, clearArgbColor);
}
}
/** Will throw an exception if not a depth texture. */
public void clearDepth(float depth)
{
if (this.texture != null)
{
COMMAND_ENCODER.clearDepthTexture(this.texture, depth);
}
}
//endregion
}
#endif
@@ -1,76 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
#if MC_VER <= MC_1_21_10
public class BlazeLodUniformBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.Std140Builder;
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import java.nio.ByteBuffer;
public class BlazeLodUniformBufferWrapper extends BlazeUniformBufferWrapper implements ILodContainerUniformBufferWrapper
{
private boolean uploaded = false;
//=============//
// constructor //
//=============//
//region
public BlazeLodUniformBufferWrapper() { super(BlazeLodUniformBufferWrapper.class.getName()); }
//endregion
//========//
// ??? //
//========//
//region
@Override
public void createUniformData(LodBufferContainer bufferContainer)
{
Vec3f modelOffset = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX()),
(float) (bufferContainer.minCornerBlockPos.getY()),
(float) (bufferContainer.minCornerBlockPos.getZ()));
// upload data //
int uniformBufferSize = new Std140SizeCalculator()
.putVec3() // uModelOffset
.get();
ByteBuffer buffer = this.getOrCreateBuffer(uniformBufferSize);
Std140Builder.intoBuffer(buffer)
.putVec3(modelOffset.x, modelOffset.y, modelOffset.z) // uModelOffset
.get();
}
@Override
public void tryUpload()
{
if (this.uploaded)
{
return;
}
this.upload();
this.uploaded = true;
}
//endregion
}
#endif
@@ -1,130 +0,0 @@
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
#if MC_VER <= MC_1_21_10
public class BlazeUniformBufferWrapper {}
#else
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IUniformBufferWrapper;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class BlazeUniformBufferWrapper implements IUniformBufferWrapper
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
private final String name;
private int cpuBufferSize = 0;
private int gpuBufferSize = 0;
private ByteBuffer cpuBuffer = null;
public GpuBuffer gpuBuffer = null;
//=============//
// constructor //
//=============//
//region
public BlazeUniformBufferWrapper(String name) { this.name = name; }
//endregion
//========//
// render //
//========//
//region
protected ByteBuffer getOrCreateBuffer(int size)
{
if (this.cpuBuffer == null
|| this.cpuBufferSize != size)
{
this.cpuBuffer = ByteBuffer.allocateDirect(size);
this.cpuBuffer.order(ByteOrder.nativeOrder());
this.cpuBufferSize = size;
}
return this.cpuBuffer;
}
@Override
public void upload() throws IllegalStateException
{
if (this.cpuBuffer == null)
{
throw new IllegalStateException("Upload called before buffer was created");
}
if (this.gpuBuffer == null
|| this.gpuBufferSize != this.cpuBufferSize)
{
if (this.gpuBuffer != null)
{
this.gpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX
| GpuBuffer.USAGE_UNIFORM;
this.gpuBuffer = GPU_DEVICE.createBuffer(this::getBufferName, usage, this.cpuBufferSize);
this.gpuBufferSize = this.cpuBufferSize;
}
int byteSize = (this.cpuBuffer.limit() - this.cpuBuffer.position());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.gpuBuffer, /*offset*/0, byteSize);
if (!bufferSlice.buffer().isClosed())
{
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.cpuBuffer);
}
else
{
LOGGER.warn("Uploading to buffer ["+this.name+"] failed due to already being closed");
}
}
private String getBufferName() { return this.name; }
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
if (this.gpuBuffer != null)
{
this.gpuBuffer.close();
}
}
//endregion
}
#endif
@@ -1,197 +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.common.render.openGl;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLElementBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Handles rendering the wireframe particles
* that are used for seeing what the system's doing.
*/
public class GlDhDebugWireframeRenderer extends AbstractDebugWireframeRenderer
{
public static GlDhDebugWireframeRenderer INSTANCE = new GlDhDebugWireframeRenderer();
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
// rendering setup
private GlShaderProgram basicShader;
private GLVertexBuffer vertexBuffer;
private GLElementBuffer indexBuffer;
private GlAbstractVertexAttribute va;
private boolean init = false;
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
//endregion
};
private static final int[] BOX_OUTLINE_INDICES = {
//region
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
//endregion
};
//=============//
// constructor //
//=============//
//region
private GlDhDebugWireframeRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.va = GlAbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicShader = new GlShaderProgram(
"assets/distanthorizons/shaders/debug/gl/vert.vert",
"assets/distanthorizons/shaders/debug/gl/frag.frag",
"vPosition"
);
this.createBuffer();
}
private void createBuffer()
{
// box vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
// outline vertex indexes
ByteBuffer boxOutlineBuffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
boxOutlineBuffer.order(ByteOrder.nativeOrder());
boxOutlineBuffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
boxOutlineBuffer.rewind();
this.indexBuffer = new GLElementBuffer(false);
this.indexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
}
//endregion
//===========//
// rendering //
//===========//
//region
@Override
public void render(RenderParams renderParams)
{
this.init();
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
GLMC.enableDepthTest();
this.basicShader.bind();
this.va.bind();
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
this.indexBuffer.bind();
super.render(renderParams);
// revert to prevent issues with the following passes
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
}
@Override
public void renderBox(Box box)
{
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.minPos.x - this.camPosFloatThisFrame.x, box.minPos.y - this.camPosFloatThisFrame.y, box.minPos.z - this.camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(box.maxPos.x - box.minPos.x, box.maxPos.y - box.minPos.y, box.maxPos.z - box.minPos.z));
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
this.basicShader.setUniform(this.basicShader.getUniformLocation("uTransform"), transformMatrix);
this.basicShader.setUniform(this.basicShader.getUniformLocation("uColor"), box.color);
GL32.glDrawElements(GL32.GL_LINES, BOX_OUTLINE_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
//endregion
}
@@ -1,474 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShaderProgram;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDhFramebuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GlQuadElementBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.texture.*;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL32;
public class GlDhMetaRenderer implements IDhMetaRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
.build();
public static final DhLogger RATE_LIMITED_LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
.maxCountPerSecond(4)
.build();
public static final GlDhMetaRenderer INSTANCE = new GlDhMetaRenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private int activeFramebufferId = -1;
private int activeColorTextureId = -1;
private int activeDepthTextureId = -1;
private int textureWidth;
private int textureHeight;
// framebuffer and texture ID's for this renderer
private IDhApiFramebuffer framebuffer;
/** will be null if MC's framebuffer is being used since MC already has a color texture */
@Nullable
private GlDhColorTexture nullableColorTexture;
private GlDhDepthTexture depthTexture;
/**
* If true the {@link GlDhMetaRenderer#framebuffer} is the same as MC's.
* This should only be true in the case of Optifine so LODs won't be overwritten when shaders are enabled.
*/
private boolean usingMcFramebuffer = false;
private boolean renderObjectsCreated = false;
/** used in case there's an API override */
public IDhApiShaderProgram shaderProgramForThisFrame;
//============//
// pre render //
//============//
//region
@Override
public void runRenderPassSetup(RenderParams renderParams)
{
boolean firstPass =
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
if (!this.renderObjectsCreated)
{
boolean setupSuccess = this.createRenderObjects();
if (!setupSuccess)
{
// shouldn't normally happen, but just in case
return;
}
this.renderObjectsCreated = true;
}
this.shaderProgramForThisFrame = GlDhTerrainShaderProgram.INSTANCE;
IDhApiShaderProgram lodShaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
if (lodShaderProgramOverride != null && this.shaderProgramForThisFrame.overrideThisFrame())
{
this.shaderProgramForThisFrame = lodShaderProgramOverride;
}
this.setGLState(renderParams, firstPass);
GlDhTerrainShaderProgram.INSTANCE.quadIBO.bind();
this.bindLightmap(renderParams.lightmap);
}
private void setGLState(
DhApiRenderParam renderEventParam,
boolean firstPass)
{
//===================//
// framebuffer setup //
//===================//
// get the active framebuffer
IDhApiFramebuffer framebuffer = this.framebuffer;
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
if (framebufferOverride != null && framebufferOverride.overrideThisFrame())
{
framebuffer = framebufferOverride;
}
this.setActiveFramebufferId(framebuffer.getId());
framebuffer.bind();
//==========//
// bindings //
//==========//
// by default draw everything as triangles
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
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
GLMC.enableDepthTest();
GLMC.glDepthFunc(GL32.GL_LESS);
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.textureWidth, this.textureHeight);
this.shaderProgramForThisFrame.bind();
//==========//
// uniforms //
//==========//
IDhApiShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
if (shaderProgramOverride != null)
{
shaderProgramOverride.fillUniformData(renderEventParam);
}
this.shaderProgramForThisFrame.fillUniformData(renderEventParam);
//===============//
// texture setup //
//===============//
// resize the textures if needed
if (MC_RENDER.getTargetFramebufferViewportWidth() != this.textureWidth
|| MC_RENDER.getTargetFramebufferViewportHeight() != this.textureHeight)
{
// just resizing the textures doesn't work when Optifine is present,
// so recreate the textures with the new size instead
this.createAndBindTextures();
}
// set the active textures
int depthTextureId = this.depthTexture.getTextureId();
this.setActiveDepthTextureId(depthTextureId);
if (this.nullableColorTexture != null)
{
int colorTextureId = this.nullableColorTexture.getTextureId();
this.setActiveColorTextureId(colorTextureId);
}
else
{
// get MC's color texture
int colorTextureId = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.setActiveColorTextureId(colorTextureId);
}
// 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
framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.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);
}
}
}
private boolean createRenderObjects()
{
if (this.renderObjectsCreated)
{
LOGGER.warn("Renderer setup called but it has already completed setup!");
return false;
}
// GLProxy should have already been created by this point, but just in case create it now
GLProxy.getInstance();
LOGGER.info("Setting up renderer");
GlDhTerrainShaderProgram.INSTANCE.quadIBO = new GlQuadElementBuffer();
GlDhTerrainShaderProgram.INSTANCE.quadIBO.reserve(LodQuadBuilder.getMaxBufferByteSize());
// create or get the frame buffer
if (AbstractOptifineAccessor.optifinePresent())
{
// use MC/Optifine's default Framebuffer so shaders won't remove the LODs
int currentFramebufferId = MC_RENDER.getTargetFramebuffer();
this.framebuffer = new GlDhFramebuffer(currentFramebufferId);
this.usingMcFramebuffer = true;
}
else
{
// normal use case
this.framebuffer = new GlDhFramebuffer();
this.usingMcFramebuffer = false;
}
// create and bind the necessary textures
this.createAndBindTextures();
if(this.framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE)
{
// This generally means something wasn't bound, IE missing either the color or depth texture
LOGGER.warn("Framebuffer ["+this.framebuffer.getId()+"] isn't complete.");
return false;
}
LOGGER.info("Renderer setup complete");
return true;
}
@SuppressWarnings( "deprecation" ) // done to ignore DhApiColorDepthTextureCreatedEvent
private void createAndBindTextures()
{
int oldWidth = this.textureWidth;
int oldHeight = this.textureHeight;
this.textureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
this.textureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
oldWidth, oldHeight,
this.textureWidth, this.textureHeight
);
// DhApiColorDepthTextureCreatedEvent needs to be kept around since old versions of Iris need it
ApiEventInjector.INSTANCE.fireAllEvents(DhApiColorDepthTextureCreatedEvent.class, new DhApiColorDepthTextureCreatedEvent.EventParam(textureCreatedParam));
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeColorDepthTextureCreatedEvent.class, textureCreatedParam);
// also update the framebuffer override if present
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
this.depthTexture = new GlDhDepthTexture(this.textureWidth, this.textureHeight, EGlDhDepthBufferFormat.DEPTH32F);
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
if (framebufferOverride != null)
{
framebufferOverride.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
}
// if we are using MC's frame buffer, a color texture is already present and shouldn't need to be bound
if (!this.usingMcFramebuffer)
{
this.nullableColorTexture = GlDhColorTexture.builder()
.setDimensions(this.textureWidth, this.textureHeight)
.setInternalFormat(EGlDhInternalTextureFormat.RGBA8)
.setPixelType(EGlDhPixelType.UNSIGNED_BYTE)
.setPixelFormat(EGlDhPixelFormat.RGBA)
.build();
this.framebuffer.addColorAttachment(0, this.nullableColorTexture.getTextureId());
if (framebufferOverride != null)
{
framebufferOverride.addColorAttachment(0, this.nullableColorTexture.getTextureId());
}
}
else
{
this.nullableColorTexture = null;
}
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
}
//endregion
//=============//
// post render //
//=============//
//region
@Override
public void runRenderPassCleanup(RenderParams renderParams)
{
boolean runningDeferredPass = (renderParams.renderPass == EDhApiRenderPass.TRANSPARENT);
if (!runningDeferredPass)
{
//===================//
// optifine clean up //
//===================//
if (this.usingMcFramebuffer)
{
// If MC's framebuffer is being used the depth needs to be cleared to prevent rendering on top of MC.
// This should only happen when Optifine shaders are being used.
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
}
}
this.unbindLightmap();
GlDhTerrainShaderProgram.INSTANCE.quadIBO.unbind();
this.shaderProgramForThisFrame.unbind();
}
@Override
public void applyToMcTexture(RenderParams renderParams) { GlDhApplyShader.INSTANCE.render(renderParams); }
//endregion
//================//
// clear textures //
//================//
//region
@Override
public void clearDhDepthAndColorTextures(RenderParams renderParams)
{
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
boolean firstPass =
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
// needs to be fired after all the textures have been created/bound
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams);
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
//this.framebuffer.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);
}
}
}
//endregion
//===============//
// API functions //
//===============//
//region
public void setActiveFramebufferId(int id) { this.activeFramebufferId = id; }
/** @return -1 if no frame buffer has been bound yet */
public int getActiveFramebufferId() { return this.activeFramebufferId; }
public void setActiveColorTextureId(int id)
{
this.activeColorTextureId = id;
DhApiRenderProxy.activeOpenGlDhColorTextureId = id;
}
/** @return -1 if no texture has been bound yet */
public int getActiveColorTextureId() { return this.activeColorTextureId; }
public void setActiveDepthTextureId(int id)
{
this.activeDepthTextureId = id;
DhApiRenderProxy.activeOpenGlDhDepthTextureId = id;
}
/** @return -1 if no texture has been bound yet */
public int getActiveDepthTextureId() { return this.activeDepthTextureId; }
//endregion
//================//
// helper methods //
//================//
//region
public void bindLightmap(ILightMapWrapper lightMapWrapper)
{
LightMapWrapper lightMap = (LightMapWrapper)lightMapWrapper;
GLMC.glActiveTexture(GL32.GL_TEXTURE0 + LightMapWrapper.GL_BOUND_INDEX);
GLMC.glBindTexture(lightMap.getOpenGlId());
}
public void unbindLightmap()
{
// strange that we don't call "glActiveTexture" here but since it's working James isn't going to change it right now (2026-03-10)
GLMC.glBindTexture(0);
}
//endregion
}
@@ -1,66 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl;
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectRenderer;
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectVertexContainer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDummyUniformData;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlDhFarFadeRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlVanillaFadeRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fog.GlDhFogRenderer;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.ssao.GlDhSSAORenderer;
import com.seibel.distanthorizons.common.render.openGl.test.GlTestTriangleRenderer;
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.*;
public class GlDhRenderApiDefinition extends AbstractDhRenderApiDefinition
{
//=========//
// getters //
//=========//
//region
public String getApiName() { return "OpenGL"; }
//endregion
//============//
// singletons //
//============//
//region
@Override public IDhMetaRenderer getMetaRenderer() { return GlDhMetaRenderer.INSTANCE; }
@Override public IDhTerrainRenderer getTerrainRenderer() { return GlDhTerrainShaderProgram.INSTANCE; }
@Override public IDhSsaoRenderer getSsaoRenderer() { return GlDhSSAORenderer.INSTANCE; }
@Override public IDhFogRenderer getFogRenderer() { return GlDhFogRenderer.INSTANCE; }
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return GlDhFarFadeRenderer.INSTANCE; }
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return GlDhDebugWireframeRenderer.INSTANCE; }
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return GlVanillaFadeRenderer.INSTANCE; }
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return GlTestTriangleRenderer.INSTANCE; }
//endregion
//===========//
// factories //
//===========//
//region
@Override public IDhGenericRenderer createGenericRenderer() { return GlGenericObjectRenderer.INSTANCE; }
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new GLVertexBuffer(); }
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new GlDummyUniformData(); }
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new GlGenericObjectVertexContainer(); }
//endregion
}
@@ -1,387 +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.common.render.openGl;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShaderProgram;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GlQuadElementBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexAttributePostGL43;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexAttributePreGL43;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import com.seibel.distanthorizons.common.render.openGl.util.vertexFormat.GlLodVertexFormat;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.math.Vec3f;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import org.lwjgl.opengl.GL32;
/**
* Handles rendering the normal LOD terrain.
* @see LodQuadBuilder
*/
public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiShaderProgram, IDhTerrainRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
.build();
public static final GlDhTerrainShaderProgram INSTANCE = new GlDhTerrainShaderProgram();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
public GlQuadElementBuffer quadIBO = null;
public final GlAbstractVertexAttribute vao;
// uniforms //
//region
public int uCombinedMatrix = -1;
public int uModelOffset = -1;
public int uWorldYOffset = -1;
public int uMircoOffset = -1;
public int uEarthRadius = -1;
public int uLightMap = -1;
// fragment shader uniforms
public int uClipDistance = -1;
public int uDitherDhRendering = -1;
// Noise Uniforms
public int uNoiseEnabled = -1;
public int uNoiseSteps = -1;
public int uNoiseIntensity = -1;
public int uNoiseDropoff = -1;
// Debug Uniform
public int uIsWhiteWorld = -1;
//endregion
//=============//
// constructor //
//=============//
//region
private GlDhTerrainShaderProgram()
{
super(
"assets/distanthorizons/shaders/shared/gl/standard.vert",
"assets/distanthorizons/shaders/shared/gl/flat_shaded.frag",
new String[]{"vPosition", "color"}
);
this.uCombinedMatrix = this.getUniformLocation("uCombinedMatrix");
this.uModelOffset = this.getUniformLocation("uModelOffset");
this.uWorldYOffset = this.getUniformLocation("uWorldYOffset");
this.uDitherDhRendering = this.getUniformLocation("uDitherDhRendering");
this.uMircoOffset = this.getUniformLocation("uMircoOffset");
this.uEarthRadius = this.getUniformLocation("uEarthRadius");
this.uLightMap = this.getUniformLocation("uLightMap");
// Fog/Clip Uniforms
this.uClipDistance = this.getUniformLocation("uClipDistance");
// Noise Uniforms
this.uNoiseEnabled = this.getUniformLocation("uNoiseEnabled");
this.uNoiseSteps = this.getUniformLocation("uNoiseSteps");
this.uNoiseIntensity = this.getUniformLocation("uNoiseIntensity");
this.uNoiseDropoff = this.getUniformLocation("uNoiseDropoff");
// Debug Uniform
this.uIsWhiteWorld = this.getUniformLocation("uIsWhiteWorld");
if (GLProxy.getInstance().vertexAttributeBufferBindingSupported)
{
this.vao = new GlVertexAttributePostGL43(); // also binds AbstractVertexAttribute
}
else
{
this.vao = new GlVertexAttributePreGL43(); // also binds AbstractVertexAttribute
}
this.vao.bind();
// short: x, y, z, meta
// meta: byte skylight, byte blocklight, byte microOffset
this.vao.setVertexAttribute(0, 0, GlVertexPointer.addUnsignedShortsPointer(4, false, true));
// byte: r, g, b, a
this.vao.setVertexAttribute(0, 1, GlVertexPointer.addUnsignedBytesPointer(4, true, false));
// byte: iris material ID, normal index, 2 spacers
this.vao.setVertexAttribute(0, 2, GlVertexPointer.addUnsignedBytesPointer(4, true, true));
try
{
int vertexByteCount = GlLodVertexFormat.DH_VERTEX_FORMAT.getByteSize();
this.vao.completeAndCheck(vertexByteCount);
}
catch (RuntimeException e)
{
System.out.println(GlLodVertexFormat.DH_VERTEX_FORMAT);
throw e;
}
}
//endregion
//=============//
// API methods //
//=============//
//region
@Override
public void bind()
{
super.bind();
this.vao.bind();
}
@Override
public void unbind()
{
super.unbind();
this.vao.unbind();
}
@Override
public void free()
{
this.vao.free();
super.free();
}
@Override
public void bindVertexBuffer(int vbo) { this.vao.bindBufferToAllBindingPoints(vbo); }
@Override
public void fillUniformData(DhApiRenderParam renderParameters)
{
Mat4f combinedMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
combinedMatrix.multiply(renderParameters.dhModelViewMatrix);
super.bind();
// uniforms
this.setUniform(this.uCombinedMatrix, combinedMatrix);
this.setUniform(this.uMircoOffset, 0.01f); // 0.01 block offset
this.setUniform(this.uLightMap, LightMapWrapper.GL_BOUND_INDEX);
this.setUniform(this.uWorldYOffset, (float) renderParameters.worldYOffset);
this.setUniform(this.uDitherDhRendering, Config.Client.Advanced.Graphics.Quality.ditherDhFade.get());
float curveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
if (curveRatio < -1.0f || curveRatio > 1.0f)
{
curveRatio = /*6371KM*/ 6371000.0f / curveRatio;
}
else
{
// disable curvature if the config value is between -1 and 1
curveRatio = 0.0f;
}
this.setUniform(this.uEarthRadius, curveRatio);
// Noise Uniforms
this.setUniform(this.uNoiseEnabled, Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get());
this.setUniform(this.uNoiseSteps, Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get());
this.setUniform(this.uNoiseIntensity, Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get());
this.setUniform(this.uNoiseDropoff, Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get());
// Debug
this.setUniform(this.uIsWhiteWorld, Config.Client.Advanced.Debugging.enableWhiteWorld.get());
// Clip Uniform
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
if (!Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
}
this.setUniform(this.uClipDistance, dhNearClipDistance);
}
@Override
public void setModelOffsetPos(DhApiVec3f modelOffsetPos) { this.setUniform(this.uModelOffset, new Vec3f(modelOffsetPos)); }
@Override
public int getId() { return this.id; }
/** The base DH render program should always render */
@Override
public boolean overrideThisFrame() { return true; }
//endregion
//===========//
// rendering //
//===========//
//region
@Override
public void render(RenderParams renderEventParam, boolean opaquePass, SortedArraySet<LodBufferContainer> bufferContainers, IProfilerWrapper profiler)
{
//=======================//
// debug wireframe setup //
//=======================//
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
if (renderWireframe)
{
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
GLMC.disableFaceCulling();
}
else
{
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
if (!opaquePass)
{
GLMC.enableBlend();
GLMC.enableDepthTest();
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
}
else
{
GLMC.disableBlend();
}
//===========//
// rendering //
//===========//
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
if (IRIS_ACCESSOR != null)
{
// done to fix a bug with Iris where face culling isn't properly set or reverted in the MC state manager
// which causes Sodium to render some water chunks with their normals inverted
// https://github.com/IrisShaders/Iris/issues/2582
// https://github.com/IrisShaders/Iris/blob/1.21.9/common/src/main/java/net/irisshaders/iris/compat/dh/LodRendererEvents.java#L346
GLMC.enableFaceCulling();
}
if (bufferContainers != null)
{
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
// set uniforms and fire events
{
Vec3d camPos = renderEventParam.exactCameraPosition;
Vec3f modelPos = new Vec3f(
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.setModelOffsetPos(modelPos);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
}
IVertexBufferWrapper[] vertexBuffers = (opaquePass ? bufferContainer.vbos : bufferContainer.vbosTransparent);
for (int vboIndex = 0; vboIndex < vertexBuffers.length; vboIndex++)
{
GLVertexBuffer vbo = (GLVertexBuffer) vertexBuffers[vboIndex];
if (vbo == null)
{
continue;
}
if (vbo.getVertexCount() == 0)
{
continue;
}
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
int indexCount = (int)(vbo.getVertexCount() * 1.5);
vbo.bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
GL32.glDrawElements(
GL32.GL_TRIANGLES,
indexCount,
this.quadIBO.getType(), 0);
vbo.unbind();
}
}
}
//=========================//
// debug wireframe cleanup //
//=========================//
if (renderWireframe)
{
// default back to GL_FILL since all other rendering uses it
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
}
//endregion
}
@@ -1,738 +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.common.render.openGl.generic;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLElementBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.lwjgl.opengl.ARBInstancedArrays;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL33;
import org.lwjgl.system.MemoryUtil;
import java.awt.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Handles rendering generic groups of {@link DhApiRenderableBox}.
*
* @see IDhApiCustomRenderRegister
* @see DhApiRenderableBox
*/
public class GlGenericObjectRenderer implements IDhGenericRenderer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
public static final GlGenericObjectRenderer INSTANCE = new GlGenericObjectRenderer();
/**
* Can be used to troubleshoot the renderer.
* If enabled several debug objects will render around (0,150,0).
*/
public static final boolean RENDER_DEBUG_OBJECTS = false;
// rendering setup
private boolean init = false;
private IDhApiGenericObjectShaderProgram instancedShaderProgram;
private IDhApiGenericObjectShaderProgram directShaderProgram;
private GLVertexBuffer boxVertexBuffer;
private GLElementBuffer boxIndexBuffer;
private boolean instancedRenderingAvailable;
private boolean vertexAttribDivisorSupported;
private boolean instancedArraysSupported;
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
//region
// Pos x y z
// min X, vertical face
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
// max X, vertical face
0, 1, 1,
1, 1, 1,
1, 0, 1,
0, 0, 1,
// min Z, vertical face
0, 0, 1,
0, 0, 0,
0, 1, 0,
0, 1, 1,
// max Z, vertical face
1, 0, 1,
1, 1, 1,
1, 1, 0,
1, 0, 0,
// min Y, horizontal face
0, 0, 1,
1, 0, 1,
1, 0, 0,
0, 0, 0,
// max Y, horizontal face
0, 1, 1,
1, 1, 1,
1, 1, 0,
0, 1, 0,
//endregion
};
private static final int[] BOX_INDICES = {
//region
// min X, vertical face
2, 1, 0,
0, 3, 2,
// max X, vertical face
6, 5, 4,
4, 7, 6,
// min Z, vertical face
10, 9, 8,
8, 11, 10,
// max Z, vertical face
14, 13, 12,
12, 15, 14,
// min Y, horizontal face
18, 17, 16,
16, 19, 18,
// max Y, horizontal face
20, 21, 22,
22, 23, 20,
//endregion
};
//=============//
// constructor //
//=============//
//region
private GlGenericObjectRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
//===================================//
// is instanced rendering available? //
//===================================//
this.vertexAttribDivisorSupported = GLProxy.getInstance().vertexAttribDivisorSupported;
this.instancedArraysSupported = GLProxy.getInstance().instancedArraysSupported;
boolean isMac = (EPlatform.get() == EPlatform.MACOS);
this.instancedRenderingAvailable = (this.vertexAttribDivisorSupported || this.instancedArraysSupported) && !isMac;
if (!this.instancedRenderingAvailable)
{
LOGGER.warn("Instanced rendering not supported by this GPU, falling back to direct rendering. Generic object rendering will be slow and some effects may be disabled.");
}
//======================//
// startup the renderer //
//======================//
this.instancedShaderProgram = new GlGenericObjectShaderProgram(true);
this.directShaderProgram = new GlGenericObjectShaderProgram(false);
this.createBuffers();
if (RENDER_DEBUG_OBJECTS)
{
this.addGenericDebugObjects();
}
}
private void createBuffers()
{
// box vertices
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.boxVertexBuffer = new GLVertexBuffer(false);
this.boxVertexBuffer.bind();
this.boxVertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
MemoryUtil.memFree(boxVerticesBuffer);
// box vertex indexes
ByteBuffer solidIndexBuffer = MemoryUtil.memAlloc(BOX_INDICES.length * Integer.BYTES);
solidIndexBuffer.asIntBuffer().put(BOX_INDICES);
solidIndexBuffer.rewind();
this.boxIndexBuffer = new GLElementBuffer(false);
this.boxIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
this.boxIndexBuffer.bind();
MemoryUtil.memFree(solidIndexBuffer);
}
private void addGenericDebugObjects()
{
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
// single giant box
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":CyanChunkBox",
new DhApiRenderableBox(
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
EDhApiBlockMaterial.WATER)
);
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleGiantBoxGroup);
// single slender box
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
ModInfo.NAME + ":GreenBeacon",
new DhApiRenderableBox(
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
EDhApiBlockMaterial.ILLUMINATED)
);
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.add(singleTallBoxGroup);
// absolute box group
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
for (int i = 0; i < 18; i++)
{
absBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
EDhApiBlockMaterial.LAVA
)
);
}
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
this.add(absolutePosBoxGroup);
// relative box group
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
for (int i = 0; i < 8; i+=2)
{
relBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
EDhApiBlockMaterial.METAL
)
);
}
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MovingMagentaGroup",
new DhApiVec3d(24, 140, 24),
relBoxList);
relativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
pos.x += event.partialTicks / 2;
pos.x %= 32;
relativePosBoxGroup.setOriginBlockPos(pos);
});
this.add(relativePosBoxGroup);
// massive relative box group
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
for (int x = 0; x < 50*2; x+=2)
{
for (int z = 0; z < 50*2; z+=2)
{
massRelBoxList.add(new DhApiRenderableBox(
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
EDhApiBlockMaterial.TERRACOTTA
)
);
}
}
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
ModInfo.NAME + ":MassRedGroup",
new DhApiVec3d(-25, 140, 0),
massRelBoxList);
massRelativePosBoxGroup.setPreRenderFunc((event) ->
{
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
blockPos.y += event.partialTicks / 4;
if (blockPos.y > 150f)
{
blockPos.y = 140f;
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
massRelativePosBoxGroup.triggerBoxChange();
}
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
});
this.add(massRelativePosBoxGroup);
}
//endregion
//==============//
// registration //
//==============//
//region
@Override
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
{
if (!(iBoxGroup instanceof RenderableBoxGroup))
{
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
}
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
long id = boxGroup.getId();
if (this.boxGroupById.containsKey(id))
{
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
}
this.boxGroupById.put(id, boxGroup);
}
@Override
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
public void clear() { this.boxGroupById.clear(); }
//endregion
//===========//
// rendering //
//===========//
//region
/**
* @param renderingWithSsao
* if true that means this render call is happening before the SSAO pass
* and any objects rendered in this pass will have SSAO applied to them.
*/
@Override
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
{
// render setup //
profiler.push("setup");
this.init();
boolean useInstancedRendering = this.instancedRenderingAvailable
&& Config.Client.Advanced.Graphics.GenericRendering.enableInstancedRendering.get();
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
if (renderWireframe)
{
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
GLMC.disableFaceCulling();
}
else
{
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
GLMC.enableBlend();
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
IDhApiGenericObjectShaderProgram shaderProgram = useInstancedRendering ? this.instancedShaderProgram : this.directShaderProgram;
IDhApiGenericObjectShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiGenericObjectShaderProgram.class);
if (shaderProgramOverride != null && shaderProgram.overrideThisFrame())
{
shaderProgram = shaderProgramOverride;
}
shaderProgram.bind(renderEventParam);
shaderProgram.bindVertexBuffer(this.boxVertexBuffer.getId());
this.boxIndexBuffer.bind();
Vec3d camPos = MC_RENDER.getCameraExactPosition();
// rendering //
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// validation //
// shouldn't happen, but just in case
if (boxGroup == null)
{
continue;
}
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled != renderingWithSsao)
{
continue;
}
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
// ignore inactive groups
if (!boxGroup.active)
{
continue;
}
// allow API users to cancel this object's rendering
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
if (cancelRendering)
{
continue;
}
// update instanced data if needed
if (useInstancedRendering)
{
boxGroup.tryUpdateInstancedDataAsync();
// skip groups that haven't been uploaded yet
if (boxGroup.vertexBufferContainer.getState() != GlGenericObjectVertexContainer.EState.RENDER)
{
continue;
}
}
// render //
profiler.popPush("rendering");
profiler.push(boxGroup.getResourceLocationNamespace());
profiler.push(boxGroup.getResourceLocationPath());
if (useInstancedRendering)
{
this.renderBoxGroupInstanced(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
}
else
{
this.renderBoxGroupDirect(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
}
profiler.pop(); // resource path
profiler.pop(); // resource namespace
boxGroup.postRender(renderEventParam);
}
//==========//
// clean up //
//==========//
profiler.popPush("cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
if (renderWireframe)
{
// default back to GL_FILL since all other rendering uses it
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GLMC.enableFaceCulling();
}
shaderProgram.unbind();
profiler.pop();
}
//endregion
//=====================//
// instanced rendering //
//=====================//
//region
private void renderBoxGroupInstanced(
IDhApiGenericObjectShaderProgram shaderProgram, DhApiRenderParam renderEventParam,
RenderableBoxGroup boxGroup, Vec3d camPos,
IProfilerWrapper profiler)
{
// update instance data //
profiler.push("vertex setup");
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DEFAULT_SHADING;
}
shaderProgram.fillIndirectUniformData(
renderEventParam,
shading, boxGroup,
camPos);
// Bind instance data //
profiler.popPush("binding");
GlGenericObjectVertexContainer container = (GlGenericObjectVertexContainer)(boxGroup.vertexBufferContainer);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.color);
GL32.glEnableVertexAttribArray(1);
GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0);
this.vertexAttribDivisor(1, 1);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.scale);
GL32.glEnableVertexAttribArray(2);
this.vertexAttribDivisor(2, 1);
GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.chunkPos);
GL32.glEnableVertexAttribArray(3);
this.vertexAttribDivisor(3, 1);
GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.subChunkPos);
GL32.glEnableVertexAttribArray(4);
this.vertexAttribDivisor(4, 1);
GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.material);
GL32.glEnableVertexAttribArray(5);
this.vertexAttribDivisor(5, 1);
GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0);
// Draw instanced
profiler.popPush("render");
if (container.uploadedBoxCount > 0)
{
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, container.uploadedBoxCount);
}
// Clean up
profiler.popPush("cleanup");
GL32.glDisableVertexAttribArray(1);
GL32.glDisableVertexAttribArray(2);
GL32.glDisableVertexAttribArray(3);
GL32.glDisableVertexAttribArray(4);
GL32.glDisableVertexAttribArray(5);
profiler.pop();
}
/**
* Clean way to handle both {@link GL33#glVertexAttribDivisor} and {@link ARBInstancedArrays#glVertexAttribDivisorARB}
* based on which one is supported.
*/
private void vertexAttribDivisor(int index, int divisor)
{
if (this.vertexAttribDivisorSupported)
{
GL33.glVertexAttribDivisor(index, divisor);
}
else if(this.instancedArraysSupported)
{
ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor);
}
else
{
throw new IllegalStateException("Instanced rendering isn't supported by this machine. Direct rendering should have been used instead.");
}
}
//endregion
//==================//
// direct rendering //
//==================//
//region
private void renderBoxGroupDirect(
IDhApiGenericObjectShaderProgram shaderProgram,
DhApiRenderParam renderEventParam,
RenderableBoxGroup boxGroup, Vec3d camPos,
IProfilerWrapper profiler)
{
profiler.popPush("shared uniforms");
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DhApiRenderableBoxGroupShading.getUnshaded();
}
shaderProgram.fillSharedDirectUniformData(renderEventParam, shading, boxGroup, camPos);
for (int i = 0; i < boxGroup.size(); i++)
{
try
{
DhApiRenderableBox box = boxGroup.get(i);
if (box != null)
{
profiler.popPush("direct uniforms");
shaderProgram.fillDirectUniformData(renderEventParam, boxGroup, box, camPos);
profiler.popPush("render");
GL32.glDrawElements(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
}
catch (IndexOutOfBoundsException e)
{
// Concurrency issue, the list was modified while rendering
// this can probably be ignored.
// However, if it does become a problem we can add locks to the box group.
break;
}
}
profiler.pop();
}
//endregion
//=========//
// getters //
//=========//
//region
/** @throws IllegalStateException if {@link #init()} function hasn't been called yet */
public boolean getInstancedRenderingAvailable() throws IllegalStateException
{
if (!this.init)
{
throw new IllegalStateException("GL initialization hasn't been completed.");
}
return this.instancedRenderingAvailable;
}
//endregion
//=========//
// F3 menu //
//=========//
//region
public String getVboRenderDebugMenuString()
{
// get counts
int totalGroupCount = this.boxGroupById.size();
int totalBoxCount = 0;
int activeGroupCount = 0;
int activeBoxCount = 0;
for (long key : this.boxGroupById.keySet())
{
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
if (renderGroup.active)
{
activeGroupCount++;
activeBoxCount += renderGroup.size();
}
totalBoxCount += renderGroup.size();
}
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
}
//endregion
}
@@ -1,231 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.generic;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3f;
public class GlGenericObjectShaderProgram extends GlShaderProgram implements IDhApiGenericObjectShaderProgram
{
public static final String VERTEX_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/vert.vert";
public static final String VERTEX_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/vert.vert";
public static final String FRAGMENT_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/frag.frag";
public static final String FRAGMENT_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/frag.frag";
public final GlAbstractVertexAttribute va;
// shader uniforms
private final int directShaderTransformUniform;
private final int directShaderColorUniform;
private final int instancedShaderOffsetChunkUniform;
private final int instancedShaderOffsetSubChunkUniform;
private final int instancedShaderCameraChunkPosUniform;
private final int instancedShaderCameraSubChunkPosUniform;
private final int instancedShaderProjectionModelViewMatrixUniform;
private final int lightMapUniform;
private final int skyLightUniform;
private final int blockLightUniform;
private final int northShadingUniform;
private final int southShadingUniform;
private final int eastShadingUniform;
private final int westShadingUniform;
private final int topShadingUniform;
private final int bottomShadingUniform;
//=============//
// constructor //
//=============//
public GlGenericObjectShaderProgram(boolean useInstancedRendering)
{
super(
useInstancedRendering ? VERTEX_SHADER_INSTANCED_PATH : VERTEX_SHADER_DIRECT_PATH,
useInstancedRendering ? FRAGMENT_SHADER_INSTANCED_PATH : FRAGMENT_SHADER_DIRECT_PATH,
"vPosition"
);
this.va = GlAbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.directShaderTransformUniform = this.tryGetUniformLocation("uTransform");
this.directShaderColorUniform = this.tryGetUniformLocation("uColor");
this.instancedShaderOffsetChunkUniform = this.tryGetUniformLocation("uOffsetChunk");
this.instancedShaderOffsetSubChunkUniform = this.tryGetUniformLocation("uOffsetSubChunk");
this.instancedShaderCameraChunkPosUniform = this.tryGetUniformLocation("uCameraPosChunk");
this.instancedShaderCameraSubChunkPosUniform = this.tryGetUniformLocation("uCameraPosSubChunk");
this.instancedShaderProjectionModelViewMatrixUniform = this.tryGetUniformLocation("uProjectionMvm");
this.lightMapUniform = this.getUniformLocation("uLightMap");
this.skyLightUniform = this.getUniformLocation("uSkyLight");
this.blockLightUniform = this.getUniformLocation("uBlockLight");
this.northShadingUniform = this.getUniformLocation("uNorthShading");
this.southShadingUniform = this.getUniformLocation("uSouthShading");
this.eastShadingUniform = this.getUniformLocation("uEastShading");
this.westShadingUniform = this.getUniformLocation("uWestShading");
this.topShadingUniform = this.getUniformLocation("uTopShading");
this.bottomShadingUniform = this.getUniformLocation("uBottomShading");
}
//=========//
// methods //
//=========//
@Override
public void bind(DhApiRenderParam renderEventParam)
{
super.bind();
this.va.bind();
}
@Override
public void unbind()
{
super.unbind();
this.va.unbind();
}
@Override
public void free()
{
this.va.free();
super.free();
}
@Override
public void bindVertexBuffer(int vbo) { this.va.bindBufferToAllBindingPoints(vbo); }
@Override
public void fillIndirectUniformData(
DhApiRenderParam renderParameters,
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
DhApiVec3d camPos
)
{
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
super.bind();
this.setUniform(this.instancedShaderOffsetChunkUniform,
new DhApiVec3i(
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
));
this.setUniform(this.instancedShaderOffsetSubChunkUniform,
new Vec3f(
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
));
this.setUniform(this.instancedShaderCameraChunkPosUniform,
new DhApiVec3i(
LodUtil.getChunkPosFromDouble(camPos.x),
LodUtil.getChunkPosFromDouble(camPos.y),
LodUtil.getChunkPosFromDouble(camPos.z)
));
this.setUniform(this.instancedShaderCameraSubChunkPosUniform,
new Vec3f(
LodUtil.getSubChunkPosFromDouble(camPos.x),
LodUtil.getSubChunkPosFromDouble(camPos.y),
LodUtil.getSubChunkPosFromDouble(camPos.z)
));
this.setUniform(this.instancedShaderProjectionModelViewMatrixUniform, projectionMvmMatrix);
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
this.setUniform(this.northShadingUniform, shading.north);
this.setUniform(this.southShadingUniform, shading.south);
this.setUniform(this.eastShadingUniform, shading.east);
this.setUniform(this.westShadingUniform, shading.west);
this.setUniform(this.topShadingUniform, shading.top);
this.setUniform(this.bottomShadingUniform, shading.bottom);
}
@Override
public void fillSharedDirectUniformData(
DhApiRenderParam renderParameters,
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
DhApiVec3d camPos)
{
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
this.setUniform(this.northShadingUniform, shading.north);
this.setUniform(this.southShadingUniform, shading.south);
this.setUniform(this.eastShadingUniform, shading.east);
this.setUniform(this.westShadingUniform, shading.west);
this.setUniform(this.topShadingUniform, shading.top);
this.setUniform(this.bottomShadingUniform, shading.bottom);
}
public void fillDirectUniformData(
DhApiRenderParam renderParameters,
IDhApiRenderableBoxGroup boxGroup, DhApiRenderableBox box,
DhApiVec3d camPos)
{
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
Mat4f boxTransform = Mat4f.createTranslateMatrix(
(float) (box.minPos.x + boxGroup.getOriginBlockPos().x - camPos.x),
(float) (box.minPos.y + boxGroup.getOriginBlockPos().y - camPos.y),
(float) (box.minPos.z + boxGroup.getOriginBlockPos().z - camPos.z));
boxTransform.multiply(Mat4f.createScaleMatrix(
(float) (box.maxPos.x - box.minPos.x),
(float) (box.maxPos.y - box.minPos.y),
(float) (box.maxPos.z - box.minPos.z)));
projectionMvmMatrix.multiply(boxTransform);
this.setUniform(this.directShaderTransformUniform, projectionMvmMatrix);
this.setUniform(this.directShaderColorUniform, box.color);
}
@Override
public int getId() { return this.id; }
/** The base DH render program should always render */
@Override
public boolean overrideThisFrame() { return true; }
}
@@ -1,180 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.generic;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import org.lwjgl.opengl.GL32;
import java.awt.*;
import java.util.List;
/**
* For use by {@link RenderableBoxGroup}
*
* @see RenderableBoxGroup
*/
public class GlGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int chunkPos = 0;
public int subChunkPos = 0;
public int scale = 0;
public int color = 0;
public int material = 0;
public int[] chunkPosData = new int[0];
public float[] subChunkPosData = new float[0];
public float[] scalingData = new float[0];
public float[] colorData = new float[0];
public int[] materialData = new int[0];
public int uploadedBoxCount = 0;
private EState state = EState.NEW;
@Override
public EState getState() { return this.state; }
@Override
public void setState(EState state) { this.state = state; }
//===========================//
// render building/uploading //
//===========================//
//region
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
{
int boxCount = uploadBoxList.size();
// recreate the data arrays if their size is different
if (this.uploadedBoxCount != boxCount)
{
this.uploadedBoxCount = boxCount;
this.chunkPosData = new int[boxCount * 3]; // 3 elements XYZ
this.subChunkPosData = new float[boxCount * 3]; // 3 elements XYZ
this.scalingData = new float[boxCount * 3]; // 3 elements XYZ
this.colorData = new float[boxCount * 4]; // 4 elements, RGBA
this.materialData = new int[boxCount];
}
// transformation / scaling //
for (int i = 0; i < boxCount; i++)
{
DhApiRenderableBox box = uploadBoxList.get(i);
int dataIndex = i * 3;
this.chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x);
this.chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y);
this.chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z);
this.subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x);
this.subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y);
this.subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z);
this.scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x);
this.scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y);
this.scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z);
}
// colors/materials //
for (int i = 0; i < boxCount; i++)
{
DhApiRenderableBox box = uploadBoxList.get(i);
Color color = box.color;
int colorIndex = i * 4;
this.colorData[colorIndex] = color.getRed() / 255.0f;
this.colorData[colorIndex + 1] = color.getGreen() / 255.0f;
this.colorData[colorIndex + 2] = color.getBlue() / 255.0f;
this.colorData[colorIndex + 3] = color.getAlpha() / 255.0f;
this.materialData[i] = box.material;
}
this.state = GlGenericObjectVertexContainer.EState.READY_TO_UPLOAD;
}
public void uploadDataToGpu()
{
this.tryCreateBuffers();
// Upload transformation matrices
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.chunkPos);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.chunkPosData, GL32.GL_DYNAMIC_DRAW);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.subChunkPos);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.subChunkPosData, GL32.GL_DYNAMIC_DRAW);
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.scale);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.scalingData, GL32.GL_DYNAMIC_DRAW);
// Upload colors
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.color);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.colorData, GL32.GL_DYNAMIC_DRAW);
// Upload materials
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.material);
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.materialData, GL32.GL_DYNAMIC_DRAW);
this.state = EState.RENDER;
}
/** needs to be done on the render thread */
private void tryCreateBuffers()
{
if (this.chunkPos == 0)
{
this.chunkPos = GLMC.glGenBuffers();
this.subChunkPos = GLMC.glGenBuffers();
this.scale = GLMC.glGenBuffers();
this.color = GLMC.glGenBuffers();
this.material = GLMC.glGenBuffers();
}
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close()
{
tryDeleteBuffer(this.chunkPos);
tryDeleteBuffer(this.subChunkPos);
tryDeleteBuffer(this.scale);
tryDeleteBuffer(this.color);
tryDeleteBuffer(this.material);
}
private static void tryDeleteBuffer(int bufferId)
{
// usually unnecessary, but just in case
if (bufferId != 0)
{
GLMC.glDeleteBuffers(bufferId);
}
}
//endregion
}
@@ -1,347 +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.common.render.openGl.glObject;
import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.GLUtil;
import java.io.PrintStream;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* A singleton that holds references to different openGL contexts
* and GPU capabilities.
*/
public class GLProxy
{
public static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
private static GLProxy instance = null;
/** Minecraft's GL capabilities */
public final GLCapabilities glCapabilities;
public boolean namedObjectSupported = false; // ~OpenGL 4.5 (UNUSED CURRENTLY)
public boolean bufferStorageSupported = false; // ~OpenGL 4.4
public boolean vertexAttributeBufferBindingSupported = false; // ~OpenGL 4.3
public boolean instancedArraysSupported = false;
public boolean vertexAttribDivisorSupported = false; // OpenGL 3.3 or newer
private final EDhApiGpuUploadMethod preferredUploadMethod;
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
);
//=============//
// constructor //
//=============//
//region
private GLProxy() throws IllegalStateException
{
// this must be created on minecraft's render context to work correctly
if (GLFW.glfwGetCurrentContext() == 0L)
{
throw new IllegalStateException(GLProxy.class.getSimpleName() + " was created outside the render thread!");
}
LOGGER.info("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see there must have been an OpenGL error.");
LOGGER.info("Lod Render OpenGL version [" + GL32.glGetString(GL32.GL_VERSION) + "].");
//============================//
// get Minecraft's GL context //
//============================//
// get Minecraft's capabilities
this.glCapabilities = GL.getCapabilities();
// crash the game if the GPU doesn't support OpenGL 3.2
if (!this.glCapabilities.OpenGL32)
{
String supportedVersionInfo = this.getFailedVersionInfo(this.glCapabilities);
// See full requirement at above.
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GLProxy.class.getSimpleName()
+ " and discovered this GPU doesn't meet the OpenGL requirements. Sorry I couldn't tell you sooner :(\n" +
"Additional info:\n" + supportedVersionInfo;
IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
MC.crashMinecraft(errorMessage, new UnsupportedOperationException("Distant Horizon OpenGL requirements not met"));
}
LOGGER.info("minecraftGlCapabilities:\n" + this.versionInfoToString(this.glCapabilities));
if (Config.Client.Advanced.Debugging.OpenGl.overrideVanillaGLLogger.get())
{
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream(GLProxy::logMessage, this.vanillaDebugMessageBuilder), true));
}
//======================//
// get GPU capabilities //
//======================//
// UNUSED currently
// Check if we can use the named version of all calls, which is available in GL4.5 or after
this.namedObjectSupported = this.glCapabilities.glNamedBufferData != 0L; //Nullptr
// Check if we can use the Buffer Storage, which is available in GL4.4 or after
this.bufferStorageSupported = this.glCapabilities.glBufferStorage != 0L; // Nullptr
if (!this.bufferStorageSupported)
{
LOGGER.info("This GPU doesn't support Buffer Storage (OpenGL 4.4), falling back to using other methods.");
}
// Check if we can use the make-over version of Vertex Attribute, which is available in GL4.3 or after
this.vertexAttributeBufferBindingSupported = this.glCapabilities.glBindVertexBuffer != 0L; // Nullptr
// used by instanced rendering
this.vertexAttribDivisorSupported = this.glCapabilities.OpenGL33;
// denotes if ARBInstancedArrays.glVertexAttribDivisorARB() is available or not
// can be used as a backup if MC didn't create a GL 3.3+ context
this.instancedArraysSupported = this.glCapabilities.GL_ARB_instanced_arrays;
// get the best automatic upload method
String vendor = GL32.glGetString(GL32.GL_VENDOR).toUpperCase(); // example return: "NVIDIA CORPORATION"
if (EPlatform.get() != EPlatform.MACOS)
{
if (vendor.contains("NVIDIA") || vendor.contains("GEFORCE"))
{
// NVIDIA card
this.preferredUploadMethod = this.bufferStorageSupported ? EDhApiGpuUploadMethod.BUFFER_STORAGE : EDhApiGpuUploadMethod.SUB_DATA;
}
else
{
// AMD or Intel card
this.preferredUploadMethod = this.bufferStorageSupported ? EDhApiGpuUploadMethod.BUFFER_STORAGE : EDhApiGpuUploadMethod.DATA;
}
}
else
{
// Mac may have an issue with Buffer Storage, so default to the most basic
// form of uploading
this.preferredUploadMethod = EDhApiGpuUploadMethod.DATA;
}
LOGGER.info("GPU Vendor [" + vendor + "] with OS [" + EPlatform.get().getName() + "], Preferred upload method is [" + this.preferredUploadMethod + "].");
//==========//
// clean up //
//==========//
// GLProxy creation success
LOGGER.info(GLProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
}
//endregion
//=========//
// getters //
//=========//
//region
public static boolean hasInstance() { return instance != null; }
/** @throws IllegalStateException if the Proxy hasn't been created yet and this is called outside the render thread */
public static GLProxy getInstance() throws IllegalStateException
{
if (instance == null)
{
instance = new GLProxy();
}
return instance;
}
public EDhApiGpuUploadMethod getGpuUploadMethod()
{
EDhApiGpuUploadMethod uploadOverride = Config.Client.Advanced.Debugging.OpenGl.glUploadMode.get();
if (uploadOverride == EDhApiGpuUploadMethod.AUTO)
{
return this.preferredUploadMethod;
}
return uploadOverride;
}
public static boolean runningOnRenderThread()
{
long currentContext = GLFW.glfwGetCurrentContext();
return currentContext != 0L; // if the context isn't null, it's the MC context
}
//endregion
//=========//
// logging //
//=========//
//region
/** this method is called on the render thread at the point of the GL Error */
private static void logMessage(GLMessage msg)
{
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
if (errorHandlingMode == EDhApiGLErrorHandlingMode.IGNORE)
{
return;
}
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
LOGGER.error(exception.getMessage(), exception);
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
{
// will probably crash the game,
// good for quickly checking if there's a problem while preventing log spam
throw exception;
}
}
else
{
// non-critical log
EGLMessageSeverity severity = msg.severity;
if (severity == null)
{
// just in case the message was malformed
severity = EGLMessageSeverity.LOW;
}
switch (severity)
{
case HIGH:
LOGGER.error(exception.getMessage(), exception);
break;
case MEDIUM:
LOGGER.warn(exception.getMessage(), exception);
break;
case LOW:
LOGGER.info(exception.getMessage(), exception);
break;
case NOTIFICATION:
LOGGER.debug(exception.getMessage(), exception);
break;
}
}
}
//endregion
//================//
// helper methods //
//================//
//region
private String getFailedVersionInfo(GLCapabilities c)
{
return "Your OpenGL support:\n" +
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n" +
"If you noticed that your computer supports higher OpenGL versions"
+ " but not the required version, try running the game in compatibility mode."
+ " (How you turn that on, I have no clue~)";
}
private String versionInfoToString(GLCapabilities c)
{
return "Your OpenGL support:\n" +
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n";
}
//endregion
}
@@ -1,259 +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.common.render.openGl.glObject;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import org.lwjgl.opengl.GL32;
public class GLState implements AutoCloseable
{
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int program;
public int vao;
public int vbo;
public int ebo;
public int fbo;
public int texture2D;
/** IE: GL_TEXTURE0, GL_TEXTURE1, etc. */
public int activeTextureNumber;
public int texture0;
public int texture1;
public int texture2;
public int texture3;
public int frameBufferTexture0;
public int frameBufferTexture1;
public int frameBufferDepthTexture;
public boolean blend;
public boolean scissor;
public int blendEqRGB;
public int blendEqAlpha;
public int blendSrcColor;
public int blendSrcAlpha;
public int blendDstColor;
public int blendDstAlpha;
public boolean depth;
public boolean writeToDepthBuffer;
public int depthFunc;
public boolean stencil;
public int stencilFunc;
public int stencilRef;
public int stencilMask;
public int[] view;
public boolean cull;
public int cullMode;
public int polyMode;
public GLState() { this.saveState(); }
public void saveState()
{
this.program = GL32.glGetInteger(GL32.GL_CURRENT_PROGRAM);
this.vao = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING);
this.vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
this.ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
this.fbo = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
this.texture2D = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
this.activeTextureNumber = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE);
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
this.texture0 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
this.texture1 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(GL32.GL_TEXTURE2); // problem with Iris
this.texture2 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
this.texture3 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
GLMC.glActiveTexture(this.activeTextureNumber);
if (this.fbo != 0)
{
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.scissor = GL32.glIsEnabled(GL32.GL_SCISSOR_TEST);
this.blendEqRGB = GL32.glGetInteger(GL32.GL_BLEND_EQUATION_RGB);
this.blendEqAlpha = GL32.glGetInteger(GL32.GL_BLEND_EQUATION_ALPHA);
this.blendSrcColor = GL32.glGetInteger(GL32.GL_BLEND_SRC_RGB);
this.blendSrcAlpha = GL32.glGetInteger(GL32.GL_BLEND_SRC_ALPHA);
this.blendDstColor = GL32.glGetInteger(GL32.GL_BLEND_DST_RGB);
this.blendDstAlpha = GL32.glGetInteger(GL32.GL_BLEND_DST_ALPHA);
this.depth = GL32.glIsEnabled(GL32.GL_DEPTH_TEST);
this.writeToDepthBuffer = GL32.glGetInteger(GL32.GL_DEPTH_WRITEMASK) == GL32.GL_TRUE;
this.depthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC);
this.stencil = GL32.glIsEnabled(GL32.GL_STENCIL_TEST);
this.stencilFunc = GL32.glGetInteger(GL32.GL_STENCIL_FUNC);
this.stencilRef = GL32.glGetInteger(GL32.GL_STENCIL_REF);
this.stencilMask = GL32.glGetInteger(GL32.GL_STENCIL_VALUE_MASK);
this.view = new int[4];
GL32.glGetIntegerv(GL32.GL_VIEWPORT, this.view);
this.cull = GL32.glIsEnabled(GL32.GL_CULL_FACE);
this.cullMode = GL32.glGetInteger(GL32.GL_CULL_FACE_MODE);
this.polyMode = GL32.glGetInteger(GL32.GL_POLYGON_MODE);
}
@Override
public void close()
{
// 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)
{
GLMC.enableBlend();
}
else
{
GLMC.disableBlend();
}
if (this.scissor)
{
GLMC.enableScissorTest();
}
else
{
GLMC.disableScissorTest();
}
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(GL32.glIsTexture(this.texture0) ? this.texture0 : 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(GL32.glIsTexture(this.texture1) ? this.texture1 : 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
GLMC.glBindTexture(GL32.glIsTexture(this.texture2) ? this.texture2 : 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
GLMC.glBindTexture(GL32.glIsTexture(this.texture3) ? this.texture3 : 0);
GLMC.glActiveTexture(this.activeTextureNumber);
GLMC.glBindTexture(GL32.glIsTexture(this.texture2D) ? this.texture2D : 0);
// attempting to set textures on the default frame buffer (ID 0) will throw errors
if (frameBufferSet)
{
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.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(this.vbo) ? this.vbo : 0);
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, GL32.glIsBuffer(this.ebo) ? this.ebo: 0);
GL32.glUseProgram(GL32.glIsProgram(this.program) ? this.program : 0);
if (this.writeToDepthBuffer)
{
GLMC.enableDepthMask();
}
else
{
GLMC.disableDepthMask();
}
GLMC.glBlendFunc(this.blendSrcColor, this.blendDstColor);
GL32.glBlendEquationSeparate(this.blendEqRGB, this.blendEqAlpha);
GLMC.glBlendFuncSeparate(this.blendSrcColor, this.blendDstColor, this.blendSrcAlpha, this.blendDstAlpha);
if (this.depth)
{
GLMC.enableDepthTest();
}
else
{
GLMC.disableDepthTest();
}
GLMC.glDepthFunc(this.depthFunc);
if (this.stencil)
{
GL32.glEnable(GL32.GL_STENCIL_TEST);
}
else
{
GL32.glDisable(GL32.GL_STENCIL_TEST);
}
GL32.glStencilFunc(this.stencilFunc, this.stencilRef, this.stencilMask);
GL32.glViewport(this.view[0], this.view[1], this.view[2], this.view[3]);
if (this.cull)
{
GLMC.enableFaceCulling();
}
else
{
GLMC.disableFaceCulling();
}
GL32.glCullFace(this.cullMode);
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, this.polyMode);
}
@Override
public String toString()
{
return "GLState{" +
"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) +
", FB text0=" + this.frameBufferTexture0 +
", FB text1=" + this.frameBufferTexture1 +
", FB depth=" + this.frameBufferDepthTexture +
", blend=" + this.blend + ", scissor=" + this.scissor + ", blendMode=" + GLEnums.getString(this.blendSrcColor) + "," + GLEnums.getString(this.blendDstColor) +
", depth=" + this.depth +
", depthFunc=" + GLEnums.getString(this.depthFunc) + ", stencil=" + this.stencil +
", stencilFunc=" + GLEnums.getString(this.stencilFunc) + ", stencilRef=" + this.stencilRef + ", stencilMask=" + this.stencilMask +
", view={x:" + this.view[0] + ", y:" + this.view[1] +
", w:" + this.view[2] + ", h:" + this.view[3] + "}" + ", cull=" + this.cull +
", cullMode=" + GLEnums.getString(this.cullMode) + ", polyMode=" + GLEnums.getString(this.polyMode) +
'}';
}
}
@@ -1,94 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import org.lwjgl.opengl.GL32;
public class GlDhFramebuffer implements IDhApiFramebuffer
{
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private int id;
//=============//
// constructor //
//=============//
//region
public GlDhFramebuffer() { this.id = GL32.glGenFramebuffers(); }
/** For internal use by Iris, do not remove. */
public GlDhFramebuffer(int id) { this.id = id; }
//endregion
//=========//
// methods //
//=========//
//region
@Override
public void addDepthAttachment(int textureId, boolean isCombinedStencil)
{
this.bind();
int depthAttachment = isCombinedStencil ? GL32.GL_DEPTH_STENCIL_ATTACHMENT : GL32.GL_DEPTH_ATTACHMENT;
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, depthAttachment, GL32.GL_TEXTURE_2D, textureId, 0);
}
@Override
public void addColorAttachment(int textureIndex, int textureId)
{
this.bind();
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0 + textureIndex, GL32.GL_TEXTURE_2D, textureId, 0);
}
@Override
public void bind()
{
if (this.id == -1)
{
throw new IllegalStateException("Framebuffer does not exist!");
}
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.id);
}
@Override
public void destroy()
{
GL32.glDeleteFramebuffers(this.id);
this.id = -1;
}
@Override
public int getStatus()
{
this.bind();
int status = GL32.glCheckFramebufferStatus(GL32.GL_FRAMEBUFFER);
return status;
}
@Override
public int getId() { return this.id; }
//endregion
//=============//
// API methods //
//=============//
//region
public boolean overrideThisFrame() { return true; }
//endregion
}
@@ -1,17 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
/**
* With OpenGL all uniform data is uploaded during the rendering phase
* so nothing is needed here.
*/
public class GlDummyUniformData implements ILodContainerUniformBufferWrapper
{
@Override public void createUniformData(LodBufferContainer bufferContainer) { }
@Override public void tryUpload() { }
@Override public void upload() { }
@Override public void close() { }
}
@@ -1,367 +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.common.render.openGl.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.ThreadUtil;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL44;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
public class GLBuffer implements AutoCloseable
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
/** the number of active buffers, can be used for debugging */
public static AtomicInteger bufferCount = new AtomicInteger(0);
private static final int PHANTOM_REF_CHECK_TIME_IN_MS = 5 * 1000;
private static final ConcurrentHashMap<PhantomReference<? extends GLBuffer>, Integer> PHANTOM_TO_BUFFER_ID = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Integer, PhantomReference<? extends GLBuffer>> BUFFER_ID_TO_PHANTOM = new ConcurrentHashMap<>();
private static final ReferenceQueue<GLBuffer> PHANTOM_REFERENCE_QUEUE = new ReferenceQueue<>();
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
protected int id;
public final int getId() { return this.id; }
protected int size = 0;
public int getSize() { return this.size; }
protected boolean bufferStorage;
public final boolean isBufferStorage() { return this.bufferStorage; }
protected boolean isMapped = false;
//==============//
// constructors //
//==============//
//region
static { CLEANUP_THREAD.execute(() -> runPhantomReferenceCleanupLoop()); }
public GLBuffer(boolean isBufferStorage) { this.create(isBufferStorage); }
//endregion
//=========//
// methods //
//=========//
//region
// Should be override by subclasses
public int getBufferBindingTarget() { return GL32.GL_COPY_READ_BUFFER; }
public void bind() { GL32.glBindBuffer(this.getBufferBindingTarget(), this.id); }
public void unbind() { GL32.glBindBuffer(this.getBufferBindingTarget(), 0); }
//endregion
//====================//
// create and destroy //
//====================//
//region
protected void create(boolean asBufferStorage)
{
if (!GLProxy.runningOnRenderThread())
{
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
}
// destroy the old buffer if one is present
// (as of 2024-12-31 James didn't see this happen, but just in case)
if (this.id != 0)
{
destroyBufferIdAsync(this.id);
}
this.id = GLMC.glGenBuffers();
this.bufferStorage = asBufferStorage;
bufferCount.getAndIncrement();
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
}
protected void destroyAsync()
{
if (this.id == 0)
{
// the buffer has already been closed
return;
}
destroyBufferIdAsync(this.id);
this.id = 0;
this.size = 0;
}
private static void destroyBufferIdAsync(int id)
{
// remove and clear the phantom reference if present
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
{
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
phantom.clear();
PHANTOM_TO_BUFFER_ID.remove(phantom);
BUFFER_ID_TO_PHANTOM.remove(id);
}
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread(() ->
{
// destroy the buffer if it exists,
// the buffer may not exist if the destroy method is called twice
if (GL32.glIsBuffer(id))
{
GLMC.glDeleteBuffers(id);
bufferCount.decrementAndGet();
if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
{
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "]");
}
}
});
}
//endregion
//==================//
// buffer uploading //
//==================//
//region
/**
* Assumes the GL Context is already bound. <br>
* Will create the VBO if one exist.
*/
public void uploadBuffer(ByteBuffer bb, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize, int bufferHint)
{
LodUtil.assertTrue(!uploadMethod.useEarlyMapping, "UploadMethod signal that this should use Mapping instead of uploadBuffer!");
int bbSize = bb.limit() - bb.position();
if (bbSize > maxExpansionSize)
{
LodUtil.assertNotReach("maxExpansionSize is [" + maxExpansionSize + "] but buffer size is [" + bbSize + "]!");
}
// Don't upload an empty buffer
if (bbSize == 0)
{
return;
}
// make sure the buffer is ready for uploading
this.createOrChangeBufferTypeForUpload(uploadMethod);
switch (uploadMethod)
{
//case NONE:
// return;
case AUTO:
LodUtil.assertNotReach("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
case BUFFER_STORAGE:
this.uploadBufferStorage(bb, bufferHint);
break;
case DATA:
this.uploadBufferData(bb, bufferHint);
break;
case SUB_DATA:
this.uploadSubData(bb, maxExpansionSize, bufferHint);
break;
default:
LodUtil.assertNotReach("Unknown GpuUploadMethod!");
}
}
/** Requires the buffer to be bound */
protected void uploadBufferStorage(ByteBuffer bb, int bufferStorageHint)
{
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
int bbSize = bb.limit() - bb.position();
this.destroyAsync();
this.create(true);
this.bind();
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, 0);
this.size = bbSize;
}
/** Requires the buffer to be bound */
protected void uploadBufferData(ByteBuffer bb, int bufferDataHint)
{
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use bufferData upload method!");
int bbSize = bb.limit() - bb.position();
GL32.glBufferData(this.getBufferBindingTarget(), bb, bufferDataHint);
this.size = bbSize;
}
/** Requires the buffer to be bound */
protected void uploadSubData(ByteBuffer bb, int maxExpansionSize, int bufferDataHint)
{
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use subData upload method!");
int bbSize = bb.limit() - bb.position();
if (this.size < bbSize || this.size > bbSize * BUFFER_SHRINK_TRIGGER)
{
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
if (newSize > maxExpansionSize) newSize = maxExpansionSize;
GL32.glBufferData(this.getBufferBindingTarget(), newSize, bufferDataHint);
this.size = newSize;
}
GL32.glBufferSubData(this.getBufferBindingTarget(), 0, bb);
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public void close() { this.destroyAsync(); }
@Override
public String toString()
{
return (this.bufferStorage ? "" : "Static-") + this.getClass().getSimpleName() +
"[id:" + this.id + ",size:" + this.size + (this.isMapped ? ",MAPPED" : "") + "]";
}
//endregion
//================//
// helper methods //
//================//
//region
/**
* Makes sure the buffer exists and is of the correct format
* before uploading.
*/
private void createOrChangeBufferTypeForUpload(EDhApiGpuUploadMethod uploadMethod)
{
// create/change the buffer type if necessary
if (uploadMethod.useBufferStorage != this.bufferStorage)
{
// recreate if the buffer storage type changed
this.bind();
this.destroyAsync();
this.create(uploadMethod.useBufferStorage);
this.bind();
}
else
{
// Prevent uploading to the null buffer (ID 0).
// This can happen if the buffer was deleted previously.
if (this.id == 0)
{
this.create(this.bufferStorage);
}
this.bind();
}
}
//endregion
//================//
// static cleanup //
//================//
//region
private static void runPhantomReferenceCleanupLoop()
{
while (true)
{
try
{
try
{
Thread.sleep(PHANTOM_REF_CHECK_TIME_IN_MS);
}
catch (InterruptedException ignore) { }
Reference<? extends GLBuffer> phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
while (phantomRef != null)
{
// destroy the buffer if it hasn't been cleared yet
if (PHANTOM_TO_BUFFER_ID.containsKey(phantomRef))
{
int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
destroyBufferIdAsync(id);
//LOGGER.warn("Buffer Phantom collected, ID: ["+id+"]");
}
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
}
}
catch (Exception e)
{
LOGGER.error("Unexpected error in buffer cleanup thread: [" + e.getMessage() + "].", e);
}
}
}
//endregion
}
@@ -1,60 +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.common.render.openGl.glObject.buffer;
import org.lwjgl.opengl.GL32;
/**
* This is a container for a OpenGL
* VBO (Vertex Buffer Object).
*
* @author James Seibel
* @version 11-20-2021
*/
public class GLElementBuffer extends GLBuffer
{
/**
* When uploading to a buffer that is too small, recreate it this many times
* bigger than the upload payload
*/
protected int indicesCount = 0;
public int getIndicesCount() { return this.indicesCount; }
protected int type = GL32.GL_UNSIGNED_INT;
public int getType() { return type; }
public GLElementBuffer(boolean isBufferStorage)
{
super(isBufferStorage);
}
@Override
public void destroyAsync()
{
super.destroyAsync();
this.indicesCount = 0;
}
@Override
public int getBufferBindingTarget()
{
return GL32.GL_ELEMENT_ARRAY_BUFFER;
}
}
@@ -1,112 +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.common.render.openGl.glObject.buffer;
import java.nio.ByteBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import org.lwjgl.opengl.GL32;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
/**
* This is a container for a OpenGL
* VBO (Vertex Buffer Object).
*
* @author James Seibel
* @version 11-20-2021
*/
public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
{
/**
* When uploading to a buffer that is too small, recreate it this many times
* bigger than the upload payload
*/
protected int vertexCount = 0;
public int getVertexCount() { return this.vertexCount; }
//=============//
// constructor //
//=============//
//region
public GLVertexBuffer() { this(GLProxy.getInstance().getGpuUploadMethod() == EDhApiGpuUploadMethod.BUFFER_STORAGE); }
public GLVertexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
//endregion
//======================//
// uploading/destroying //
//======================//
//region
@Override
public int getBufferBindingTarget() { return GL32.GL_ARRAY_BUFFER; }
@Override
public void upload(ByteBuffer buffer, int vertexCount)
{
EDhApiGpuUploadMethod uploadMethod = GLProxy.getInstance().getGpuUploadMethod();
int maxBufferSize = LodQuadBuilder.getMaxBufferByteSize();
this.uploadBuffer(buffer, vertexCount, uploadMethod, maxBufferSize);
}
/**
* bufferSize is the number of shared verticies. <br>
* This number will be higher when actually rendered since each box's face needs 2 triangles
* with 2 shared verticies.
*/
public void uploadBuffer(ByteBuffer byteBuffer, int vertexCount, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize)
{
if (vertexCount < 0)
{
throw new IllegalArgumentException("vertexCount is negative!");
}
// If size is zero, just ignore it.
if (byteBuffer.limit() - byteBuffer.position() != 0)
{
boolean useBuffStorage = uploadMethod.useBufferStorage;
super.uploadBuffer(byteBuffer, uploadMethod, maxExpansionSize, useBuffStorage ? 0 : GL32.GL_STATIC_DRAW);
}
this.vertexCount = vertexCount;
}
@Override
public void close() { this.destroyAsync(); }
@Override
public void destroyAsync()
{
super.destroyAsync();
this.vertexCount = 0;
}
//endregion
}
@@ -1,192 +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.common.render.openGl.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
/** AKA Index Buffer TODO RENAME */
public class GlQuadElementBuffer extends GLElementBuffer
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
//=============//
// constructor //
//=============//
//region
public GlQuadElementBuffer() { super(false); }
public void reserve(int quadCount)
{
if (quadCount < 0)
{
throw new IllegalArgumentException("quadCount must be greater than 0");
}
if (quadCount == 0)
{
// shouldn't happen, but just in case
return;
}
this.indicesCount = quadCount * 6; // 2 triangles per quad
if (this.indicesCount >= this.getCapacity()
&& this.indicesCount < this.getCapacity() * BUFFER_SHRINK_TRIGGER)
{
return;
}
int vertexCount = quadCount * 4; // 4 vertices per quad
if (vertexCount < 255)
{
// Reserve 1 for the reset index
this.type = GL32.GL_UNSIGNED_BYTE;
}
else if (vertexCount < 65535)
{
// Reserve 1 for the reset index
this.type = GL32.GL_UNSIGNED_SHORT;
}
else
{
this.type = GL32.GL_UNSIGNED_INT;
}
ByteBuffer buffer = MemoryUtil.memAlloc(this.indicesCount * GLEnums.getTypeSize(this.type));
buildBuffer(quadCount, buffer, this.type);
this.bind();
super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA,
this.indicesCount * GLEnums.getTypeSize(this.type), GL32.GL_STATIC_DRAW);
MemoryUtil.memFree(buffer);
}
//endregion
//=========//
// getters //
//=========//
//region
public int getCapacity() { return super.getSize() / GLEnums.getTypeSize(this.getType()); }
//endregion
//==========//
// building //
//==========//
//region
public static void buildBuffer(int quadCount, ByteBuffer buffer, int type)
{
switch (type)
{
case GL32.GL_UNSIGNED_BYTE:
buildBufferByte(quadCount, buffer);
break;
case GL32.GL_UNSIGNED_SHORT:
buildBufferShort(quadCount, buffer);
break;
case GL32.GL_UNSIGNED_INT:
buildBufferInt(quadCount, buffer);
break;
default:
throw new IllegalStateException("Unknown buffer type: [" + type + "].");
}
}
private static void buildBufferByte(int quadCount, ByteBuffer buffer)
{
for (int i = 0; i < quadCount; i++)
{
int vIndex = i * 4;
// First triangle
buffer.put((byte) (vIndex));
buffer.put((byte) (vIndex + 1));
buffer.put((byte) (vIndex + 2));
// Second triangle
buffer.put((byte) (vIndex + 2));
buffer.put((byte) (vIndex + 3));
buffer.put((byte) (vIndex));
}
if (buffer.hasRemaining())
{
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
}
buffer.rewind();
}
private static void buildBufferShort(int quadCount, ByteBuffer buffer)
{
for (int i = 0; i < quadCount; i++)
{
int vIndex = i * 4;
// First triangle
buffer.putShort((short) (vIndex));
buffer.putShort((short) (vIndex + 1));
buffer.putShort((short) (vIndex + 2));
// Second triangle
buffer.putShort((short) (vIndex + 2));
buffer.putShort((short) (vIndex + 3));
buffer.putShort((short) (vIndex));
}
if (buffer.hasRemaining())
{
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
}
buffer.rewind();
}
private static void buildBufferInt(int quadCount, ByteBuffer buffer)
{
for (int i = 0; i < quadCount; i++)
{
int vIndex = i * 4;
// First triangle
buffer.putInt(vIndex);
buffer.putInt(vIndex + 1);
buffer.putInt(vIndex + 2);
// Second triangle
buffer.putInt(vIndex + 2);
buffer.putInt(vIndex + 3);
buffer.putInt(vIndex);
}
if (buffer.hasRemaining())
{
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
}
buffer.rewind();
}
//endregion
}
@@ -1,9 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.enums;
public enum EGlVersion
{
GL_11,
GL_12,
GL_30,
GL_31
}
@@ -1,261 +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.common.render.openGl.glObject.enums;
import static org.lwjgl.opengl.GL46.*;
// Turns GL int enums back to readable strings
public class GLEnums
{
public static String getString(int glEnum)
{
// blend stuff
switch (glEnum)
{
case GL_ZERO:
return "GL_ZERO";
case GL_ONE:
return "GL_ONE";
case GL_SRC_COLOR:
return "GL_SRC_COLOR";
case GL_ONE_MINUS_SRC_COLOR:
return "GL_ONE_MINUS_SRC_COLOR";
case GL_DST_COLOR:
return "GL_DST_COLOR";
case GL_ONE_MINUS_DST_COLOR:
return "GL_ONE_MINUS_DST_COLOR";
case GL_SRC_ALPHA:
return "GL_SRC_ALPHA";
case GL_ONE_MINUS_SRC_ALPHA:
return "GL_ONE_MINUS_SRC_ALPHA";
case GL_DST_ALPHA:
return "GL_DST_ALPHA";
case GL_ONE_MINUS_DST_ALPHA:
return "GL_ONE_MINUS_DST_ALPHA";
case GL_CONSTANT_COLOR:
return "GL_CONSTANT_COLOR";
case GL_ONE_MINUS_CONSTANT_COLOR:
return "GL_ONE_MINUS_CONSTANT_COLOR";
case GL_CONSTANT_ALPHA:
return "GL_CONSTANT_ALPHA";
case GL_ONE_MINUS_CONSTANT_ALPHA:
return "GL_ONE_MINUS_CONSTANT_ALPHA";
default:
}
// shader stuff
switch (glEnum)
{
case GL_VERTEX_SHADER:
return "GL_VERTEX_SHADER";
case GL_GEOMETRY_SHADER:
return "GL_GEOMETRY_SHADER";
case GL_FRAGMENT_SHADER:
return "GL_FRAGMENT_SHADER";
default:
}
// stencil stuff
switch (glEnum)
{
case GL_KEEP:
return "GL_KEEP";
case GL_ZERO:
return "GL_ZERO";
case GL_REPLACE:
return "GL_REPLACE";
case GL_INCR:
return "GL_INCR";
case GL_DECR:
return "GL_DECR";
case GL_INVERT:
return "GL_INVERT";
case GL_INCR_WRAP:
return "GL_INCR_WRAP";
case GL_DECR_WRAP:
return "GL_DECR_WRAP";
default:
}
// depth stuff
switch (glEnum)
{
case GL_NEVER:
return "GL_NEVER";
case GL_LESS:
return "GL_LESS";
case GL_EQUAL:
return "GL_EQUAL";
case GL_LEQUAL:
return "GL_LEQUAL";
case GL_GREATER:
return "GL_GREATER";
case GL_NOTEQUAL:
return "GL_NOTEQUAL";
case GL_GEQUAL:
return "GL_GEQUAL";
case GL_ALWAYS:
return "GL_ALWAYS";
default:
}
// Texture binding points
switch (glEnum)
{
case GL_TEXTURE0:
return "GL_TEXTURE0";
case GL_TEXTURE1:
return "GL_TEXTURE1";
case GL_TEXTURE2:
return "GL_TEXTURE2";
case GL_TEXTURE3:
return "GL_TEXTURE3";
case GL_TEXTURE4:
return "GL_TEXTURE4";
case GL_TEXTURE5:
return "GL_TEXTURE5";
case GL_TEXTURE6:
return "GL_TEXTURE6";
case GL_TEXTURE7:
return "GL_TEXTURE7";
case GL_TEXTURE8:
return "GL_TEXTURE8";
case GL_TEXTURE9:
return "GL_TEXTURE9";
case GL_TEXTURE10:
return "GL_TEXTURE10";
case GL_TEXTURE11:
return "GL_TEXTURE11";
case GL_TEXTURE12:
return "GL_TEXTURE12";
case GL_TEXTURE13:
return "GL_TEXTURE13";
case GL_TEXTURE14:
return "GL_TEXTURE14";
case GL_TEXTURE15:
return "GL_TEXTURE15";
case GL_TEXTURE16:
return "GL_TEXTURE16";
case GL_TEXTURE17:
return "GL_TEXTURE17";
case GL_TEXTURE18:
return "GL_TEXTURE18";
case GL_TEXTURE19:
return "GL_TEXTURE19";
case GL_TEXTURE20:
return "GL_TEXTURE20";
case GL_TEXTURE21:
return "GL_TEXTURE21";
case GL_TEXTURE22:
return "GL_TEXTURE22";
case GL_TEXTURE23:
return "GL_TEXTURE23";
case GL_TEXTURE24:
return "GL_TEXTURE24";
case GL_TEXTURE25:
return "GL_TEXTURE25";
case GL_TEXTURE26:
return "GL_TEXTURE26";
case GL_TEXTURE27:
return "GL_TEXTURE27";
case GL_TEXTURE28:
return "GL_TEXTURE28";
case GL_TEXTURE29:
return "GL_TEXTURE29";
case GL_TEXTURE30:
return "GL_TEXTURE30";
case GL_TEXTURE31:
return "GL_TEXTURE31";
default:
}
// Polygon modes
switch (glEnum)
{
case GL_POINT:
return "GL_POINT";
case GL_LINE:
return "GL_LINE";
case GL_FILL:
return "GL_FILL";
default:
}
// Culling modes
switch (glEnum)
{
case GL_FRONT:
return "GL_FRONT";
case GL_BACK:
return "GL_BACK";
case GL_FRONT_AND_BACK:
return "GL_FRONT_AND_BACK";
default:
}
// Types
switch (glEnum)
{
case GL_BYTE:
return "GL_BYTE";
case GL_UNSIGNED_BYTE:
return "GL_UNSIGNED_BYTE";
case GL_SHORT:
return "GL_SHORT";
case GL_UNSIGNED_SHORT:
return "GL_UNSIGNED_SHORT";
case GL_INT:
return "GL_INT";
case GL_UNSIGNED_INT:
return "GL_UNSIGNED_INT";
case GL_FLOAT:
return "GL_FLOAT";
case GL_DOUBLE:
return "GL_DOUBLE";
default:
}
return "GL_UNKNOWN(" + glEnum + ")";
}
public static int getTypeSize(int glTypeEnum)
{
switch (glTypeEnum)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return 1;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
return 2;
case GL_INT:
case GL_UNSIGNED_INT:
return 4;
case GL_FLOAT:
return 4;
case GL_DOUBLE:
return 8;
default:
throw new IllegalArgumentException("Unknown type enum: " + getString(glTypeEnum));
}
}
}
@@ -1,184 +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.common.render.openGl.glObject.shader;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.lwjgl.PointerBuffer;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL32C;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.system.NativeType;
/**
* This object holds a OpenGL reference to a shader
* and allows for reading in and compiling a shader file.
*/
public class GlShader
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
/** OpenGL shader ID */
public final int id;
//==============//
// constructors //
//==============//
//region
/**
* Creates a shader with specified type.
*
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
* @param sourceString File path of the shader
* @throws RuntimeException if the shader fails to compile
*/
public GlShader(int type, String sourceString)
{
LOGGER.info("Loading shader with type: ["+type+"]");
LOGGER.debug("Source: \n["+sourceString+"]");
if (sourceString == null || sourceString.isEmpty())
{
throw new IllegalArgumentException("No shader source given.");
}
// 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+"].");
}
safeShaderSource(this.id, sourceString);
GL32.glCompileShader(this.id);
// check if the shader compiled
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
if (status != GL32.GL_TRUE)
{
String message = "Shader compiler error. Details: [" + GL32.glGetShaderInfoLog(this.id) + "]\n";
message += "Source: \n[" + sourceString + "]";
this.free(); // important!
throw new RuntimeException(message);
}
LOGGER.info("Shader loaded sucessfully.");
}
//endregion
//=========//
// helpers //
//=========//
//region
/**
* Identical in function to {@link GL32C#glShaderSource(int, CharSequence)} but
* passes a null pointer for string length to force the driver to rely on the null
* terminator for string length. This is a workaround for an apparent flaw with some
* AMD drivers that don't receive or interpret the length correctly, resulting in
* an access violation when the driver tries to read past the string memory.
*
* <p>Hat tip to fewizz for the find and the fix.
*
* <p>Source: https://github.com/vram-guild/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96
*/
private static void safeShaderSource(@NativeType("GLuint") int glId, @NativeType("GLchar const **") CharSequence source)
{
final MemoryStack stack = MemoryStack.stackGet();
final int stackPointer = stack.getPointer();
try
{
final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true);
final PointerBuffer pointers = stack.mallocPointer(1);
pointers.put(sourceBuffer);
GL32.nglShaderSource(glId, 1, pointers.address0(), 0);
org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1);
}
finally
{
stack.setPointer(stackPointer);
}
}
public void free() { GL32.glDeleteShader(this.id); }
public static String loadFile(String path, boolean absoluteFilePath)
{
StringBuilder stringBuilder = new StringBuilder();
try
{
// open the file
InputStream in;
if (absoluteFilePath)
{
// Throws FileNotFoundException
in = new FileInputStream(path); // Note: this should use OS path seperator
}
else
{
in = GlShader.class.getClassLoader().getResourceAsStream(path); // Note: path seperator should be '/'
if (in == null)
{
throw new FileNotFoundException("Shader file not found in resource: " + path);
}
}
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
// read in the file
String line;
while ((line = reader.readLine()) != null)
{
stringBuilder.append(line).append("\n");
}
}
catch (IOException e)
{
throw new RuntimeException("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
}
return stringBuilder.toString();
}
//endregion
}
@@ -1,225 +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.common.render.openGl.glObject.shader;
import java.awt.Color;
import java.nio.FloatBuffer;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryStack;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3f;
/**
* This object holds the reference to a OpenGL shader program
* and contains a few methods that can be used with OpenGL shader programs.
* The reason for many of these simple wrapper methods is as reminders of what
* can (and needs to be) done with a shader program.
*/
public class GlShaderProgram
{
/** Stores the handle of the program. */
public final int id;
//=============//
// constructor //
//=============//
//region
public GlShaderProgram(String vertResourcePath, String fragResourcePath, String attribute) { this(vertResourcePath, fragResourcePath, new String[]{ attribute }); }
/**
* @param vertResourcePath the relative path the vertex shader should be found
* @param fragResourcePath the relative path the fragment shader should be found
*/
public GlShaderProgram(String vertResourcePath, String fragResourcePath, String[] attributes)
{
this.id = GL32.glCreateProgram();
{
String shaderString = GlShader.loadFile(vertResourcePath, false);
GlShader vertShader = new GlShader(GL32.GL_VERTEX_SHADER, shaderString);
GL32.glAttachShader(this.id, vertShader.id);
vertShader.free();
}
{
String shaderString = GlShader.loadFile(fragResourcePath, false);
GlShader fragShader = new GlShader(GL32.GL_FRAGMENT_SHADER, shaderString);
GL32.glAttachShader(this.id, fragShader.id);
fragShader.free();
}
for (int i = 0; i < attributes.length; i++)
{
GL32.glBindAttribLocation(this.id, i, attributes[i]);
}
GL32.glLinkProgram(this.id);
int status = GL32.glGetProgrami(this.id, GL32.GL_LINK_STATUS);
if (status != GL32.GL_TRUE)
{
String message = "Shader Link Error. Details: " + GL32.glGetProgramInfoLog(this.id);
this.free(); // important!
throw new RuntimeException(message);
}
GL32.glUseProgram(this.id); // This HAVE to be a direct call to prevent calling the overloaded version
}
//endregion
//=========//
// binding //
//=========//
//region
public void bind() { GL32.glUseProgram(this.id); }
public void unbind() { GL32.glUseProgram(0); }
public void free() { GL32.glDeleteProgram(this.id); }
//endregion
//============//
// attributes //
//============//
//region
/**
* WARNING: Slow native call! Cache it if possible!
* Gets the location of an attribute variable with specified name.
* Calls GL20.glGetAttribLocation(id, name)
*
* @param name Attribute name
* @return Location of the attribute
* @throws RuntimeException if attribute not found
*/
public int getAttributeLocation(CharSequence name)
{
int i = GL32.glGetAttribLocation(id, name);
if (i == -1) throw new RuntimeException("Attribute name not found: " + name);
return i;
}
/**
* Same as above but without throwing errors. <br>
* Returns -1 if the attribute doesn't exist or has been optimized out.
*/
public int tryGetAttributeLocation(CharSequence name)
{ return GL32.glGetAttribLocation(this.id, name); }
//endregion
//==========//
// uniforms //
//==========//
//region
/**
* WARNING: Slow native call! Cache it if possible!
* Gets the location of a uniform variable with specified name.
* Calls GL20.glGetUniformLocation(id, name)
*
* @param name Uniform name
* @return Location of the Uniform
* @throws RuntimeException if uniform not found
*/
public int getUniformLocation(CharSequence name) throws RuntimeException
{
int i = GL32.glGetUniformLocation(id, name);
if (i == -1)
{
throw new RuntimeException("Uniform name not found: " + name);
}
return i;
}
// Same as above but without throwing errors.
// Return -1 if uniform doesn't exist or has been optimized out
public int tryGetUniformLocation(CharSequence name)
{ return GL32.glGetUniformLocation(this.id, name); }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, boolean value) { GL32.glUniform1i(location, value ? 1 : 0); }
/** @see GlShaderProgram#setUniform(int, boolean) */
public void trySetUniform(int location, boolean value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, int value) { GL32.glUniform1i(location, value); }
/** @see GlShaderProgram#setUniform(int, int) */
public void trySetUniform(int location, int value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, float value) { GL32.glUniform1f(location, value); }
/** @see GlShaderProgram#setUniform(int, float) */
public void trySetUniform(int location, float value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, Vec3f value) { GL32.glUniform3f(location, value.x, value.y, value.z); }
/** @see GlShaderProgram#setUniform(int, Vec3f) */
public void trySetUniform(int location, Vec3f value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, DhApiVec3i value) { GL32.glUniform3i(location, value.x, value.y, value.z); }
/** @see GlShaderProgram#setUniform(int, Mat4f) */
public void trySetUniform(int location, DhApiVec3i value) { if (location != -1) { this.setUniform(location, value); } }
/** Requires a bound ShaderProgram. */
public void setUniform(int location, Mat4f value)
{
try (MemoryStack stack = MemoryStack.stackPush())
{
FloatBuffer buffer = stack.mallocFloat(4 * 4);
value.store(buffer);
GL32.glUniformMatrix4fv(location, false, buffer);
}
}
/** @see GlShaderProgram#setUniform(int, Mat4f) */
public void trySetUniform(int location, Mat4f value) { if (location != -1) { this.setUniform(location, value); } }
/**
* Converts the color's RGBA values into values between 0 and 1. <br>
* Requires a bound ShaderProgram.
*/
public void setUniform(int location, Color value)
{
GL32.glUniform4f(location,
value.getRed() / 256.0f,
value.getGreen() / 256.0f,
value.getBlue() / 256.0f,
value.getAlpha() / 256.0f);
}
/** @see GlShaderProgram#setUniform(int, Color) */
public void trySetUniform(int location, Color value) { if (location != -1) { this.setUniform(location, value); } }
//endregion
}
@@ -1,114 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL30C;
import org.lwjgl.opengl.GL43C;
public enum EGlDhDepthBufferFormat
{
DEPTH(false),
DEPTH16(false),
DEPTH24(false),
DEPTH32(false),
DEPTH32F(false),
DEPTH_STENCIL(true),
DEPTH24_STENCIL8(true),
DEPTH32F_STENCIL8(true);
private final boolean combinedStencil;
EGlDhDepthBufferFormat(boolean combinedStencil) { this.combinedStencil = combinedStencil; }
@Nullable
public static EGlDhDepthBufferFormat fromGlEnum(int glenum)
{
switch (glenum)
{
case GL30C.GL_DEPTH_COMPONENT:
return EGlDhDepthBufferFormat.DEPTH;
case GL30C.GL_DEPTH_COMPONENT16:
return EGlDhDepthBufferFormat.DEPTH16;
case GL30C.GL_DEPTH_COMPONENT24:
return EGlDhDepthBufferFormat.DEPTH24;
case GL30C.GL_DEPTH_COMPONENT32:
return EGlDhDepthBufferFormat.DEPTH32;
case GL30C.GL_DEPTH_COMPONENT32F:
return EGlDhDepthBufferFormat.DEPTH32F;
case GL30C.GL_DEPTH_STENCIL:
return EGlDhDepthBufferFormat.DEPTH_STENCIL;
case GL30C.GL_DEPTH24_STENCIL8:
return EGlDhDepthBufferFormat.DEPTH24_STENCIL8;
case GL30C.GL_DEPTH32F_STENCIL8:
return EGlDhDepthBufferFormat.DEPTH32F_STENCIL8;
default:
return null;
}
}
public static EGlDhDepthBufferFormat fromGlEnumOrDefault(int glenum)
{
EGlDhDepthBufferFormat format = fromGlEnum(glenum);
if (format == null)
{
// yolo, just assume it's GL_DEPTH_COMPONENT
return EGlDhDepthBufferFormat.DEPTH;
}
return format;
}
public int getGlInternalFormat()
{
switch (this)
{
case DEPTH:
return GL30C.GL_DEPTH_COMPONENT;
case DEPTH16:
return GL30C.GL_DEPTH_COMPONENT16;
case DEPTH24:
return GL30C.GL_DEPTH_COMPONENT24;
case DEPTH32:
return GL30C.GL_DEPTH_COMPONENT32;
case DEPTH32F:
return GL30C.GL_DEPTH_COMPONENT32F;
case DEPTH_STENCIL:
return GL30C.GL_DEPTH_STENCIL;
case DEPTH24_STENCIL8:
return GL30C.GL_DEPTH24_STENCIL8;
case DEPTH32F_STENCIL8:
return GL30C.GL_DEPTH32F_STENCIL8;
}
throw new AssertionError("unreachable");
}
public int getGlType() { return isCombinedStencil() ? GL30C.GL_DEPTH_STENCIL : GL30C.GL_DEPTH_COMPONENT; }
public int getGlFormat()
{
switch (this)
{
case DEPTH:
case DEPTH16:
return GL43C.GL_UNSIGNED_SHORT;
case DEPTH24:
case DEPTH32:
return GL43C.GL_UNSIGNED_INT;
case DEPTH32F:
return GL30C.GL_FLOAT;
case DEPTH_STENCIL:
case DEPTH24_STENCIL8:
return GL30C.GL_UNSIGNED_INT_24_8;
case DEPTH32F_STENCIL8:
return GL30C.GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
}
throw new AssertionError("unreachable");
}
public boolean isCombinedStencil() { return combinedStencil; }
}
@@ -1,131 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.EGlVersion;
import org.lwjgl.opengl.GL11C;
import org.lwjgl.opengl.GL30C;
import org.lwjgl.opengl.GL31C;
import java.util.Locale;
import java.util.Optional;
public enum EGlDhInternalTextureFormat
{
RGBA(GL11C.GL_RGBA, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
// 8-bit normalized
R8(GL30C.GL_R8, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG8(GL30C.GL_RG8, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB8(GL11C.GL_RGB8, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
RGBA8(GL11C.GL_RGBA8, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
// 8-bit signed normalized
R8_SNORM(GL31C.GL_R8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RED),
RG8_SNORM(GL31C.GL_RG8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RG),
RGB8_SNORM(GL31C.GL_RGB8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGB),
RGBA8_SNORM(GL31C.GL_RGBA8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGBA),
// 16-bit normalized
R16(GL30C.GL_R16, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG16(GL30C.GL_RG16, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB16(GL11C.GL_RGB16, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
RGBA16(GL11C.GL_RGBA16, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
// 16-bit signed normalized
R16_SNORM(GL31C.GL_R16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RED),
RG16_SNORM(GL31C.GL_RG16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RG),
RGB16_SNORM(GL31C.GL_RGB16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGB),
RGBA16_SNORM(GL31C.GL_RGBA16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGBA),
// 16-bit float
R16F(GL30C.GL_R16F, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG16F(GL30C.GL_RG16F, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB16F(GL30C.GL_RGB16F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
RGBA16F(GL30C.GL_RGBA16F, EGlVersion.GL_30, EGlDhPixelFormat.RGBA),
// 32-bit float
R32F(GL30C.GL_R32F, EGlVersion.GL_30, EGlDhPixelFormat.RED),
RG32F(GL30C.GL_RG32F, EGlVersion.GL_30, EGlDhPixelFormat.RG),
RGB32F(GL30C.GL_RGB32F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
RGBA32F(GL30C.GL_RGBA32F, EGlVersion.GL_30, EGlDhPixelFormat.RGBA),
// 8-bit integer
R8I(GL30C.GL_R8I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG8I(GL30C.GL_RG8I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB8I(GL30C.GL_RGB8I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA8I(GL30C.GL_RGBA8I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 8-bit unsigned integer
R8UI(GL30C.GL_R8UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG8UI(GL30C.GL_RG8UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB8UI(GL30C.GL_RGB8UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA8UI(GL30C.GL_RGBA8UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 16-bit integer
R16I(GL30C.GL_R16I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG16I(GL30C.GL_RG16I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB16I(GL30C.GL_RGB16I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA16I(GL30C.GL_RGBA16I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 16-bit unsigned integer
R16UI(GL30C.GL_R16UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG16UI(GL30C.GL_RG16UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB16UI(GL30C.GL_RGB16UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA16UI(GL30C.GL_RGBA16UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 32-bit integer
R32I(GL30C.GL_R32I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG32I(GL30C.GL_RG32I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB32I(GL30C.GL_RGB32I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA32I(GL30C.GL_RGBA32I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// 32-bit unsigned integer
R32UI(GL30C.GL_R32UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
RG32UI(GL30C.GL_RG32UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
RGB32UI(GL30C.GL_RGB32UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
RGBA32UI(GL30C.GL_RGBA32UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
// Mixed
R3_G3_B2(GL11C.GL_R3_G3_B2, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
RGB5_A1(GL11C.GL_RGB5_A1, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
RGB10_A2(GL11C.GL_RGB10_A2, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
R11F_G11F_B10F(GL30C.GL_R11F_G11F_B10F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
RGB9_E5(GL30C.GL_RGB9_E5, EGlVersion.GL_30, EGlDhPixelFormat.RGB);
private final int glFormat;
private final EGlVersion minimumGlVersion;
private final EGlDhPixelFormat expectedPixelFormat;
EGlDhInternalTextureFormat(int glFormat, EGlVersion minimumGlVersion, EGlDhPixelFormat expectedPixelFormat)
{
this.glFormat = glFormat;
this.minimumGlVersion = minimumGlVersion;
this.expectedPixelFormat = expectedPixelFormat;
}
public static Optional<EGlDhInternalTextureFormat> fromString(String name)
{
try
{
return Optional.of(EGlDhInternalTextureFormat.valueOf(name.toUpperCase(Locale.US)));
}
catch (IllegalArgumentException e)
{
return Optional.empty();
}
}
public int getGlFormat() { return this.glFormat; }
public EGlDhPixelFormat getPixelFormat() { return this.expectedPixelFormat; }
public EGlVersion getMinimumGlVersion() { return this.minimumGlVersion; }
}
@@ -1,61 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.EGlVersion;
import org.lwjgl.opengl.GL11C;
import org.lwjgl.opengl.GL12C;
import org.lwjgl.opengl.GL30C;
import java.util.Locale;
import java.util.Optional;
public enum EGlDhPixelFormat
{
RED(GL11C.GL_RED, EGlVersion.GL_11, false),
RG(GL30C.GL_RG, EGlVersion.GL_30, false),
RGB(GL11C.GL_RGB, EGlVersion.GL_11, false),
BGR(GL12C.GL_BGR, EGlVersion.GL_12, false),
RGBA(GL11C.GL_RGBA, EGlVersion.GL_11, false),
BGRA(GL12C.GL_BGRA, EGlVersion.GL_12, false),
RED_INTEGER(GL30C.GL_RED_INTEGER, EGlVersion.GL_30, true),
RG_INTEGER(GL30C.GL_RG_INTEGER, EGlVersion.GL_30, true),
RGB_INTEGER(GL30C.GL_RGB_INTEGER, EGlVersion.GL_30, true),
BGR_INTEGER(GL30C.GL_BGR_INTEGER, EGlVersion.GL_30, true),
RGBA_INTEGER(GL30C.GL_RGBA_INTEGER, EGlVersion.GL_30, true),
BGRA_INTEGER(GL30C.GL_BGRA_INTEGER, EGlVersion.GL_30, true);
private final int glFormat;
private final EGlVersion minimumGlVersion;
private final boolean isInteger;
EGlDhPixelFormat(int glFormat, EGlVersion minimumGlVersion, boolean isInteger)
{
this.glFormat = glFormat;
this.minimumGlVersion = minimumGlVersion;
this.isInteger = isInteger;
}
public static Optional<EGlDhPixelFormat> fromString(String name)
{
try
{
return Optional.of(EGlDhPixelFormat.valueOf(name.toUpperCase(Locale.US)));
}
catch (IllegalArgumentException e)
{
return Optional.empty();
}
}
public int getGlFormat() { return this.glFormat; }
public EGlVersion getMinimumGlVersion() { return this.minimumGlVersion; }
public boolean isInteger() { return this.isInteger; }
}
@@ -1,65 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.EGlVersion;
import org.lwjgl.opengl.GL11C;
import org.lwjgl.opengl.GL12C;
import org.lwjgl.opengl.GL30C;
import java.util.Locale;
import java.util.Optional;
public enum EGlDhPixelType
{
BYTE(GL11C.GL_BYTE, EGlVersion.GL_11),
SHORT(GL11C.GL_SHORT, EGlVersion.GL_11),
INT(GL11C.GL_INT, EGlVersion.GL_11),
HALF_FLOAT(GL30C.GL_HALF_FLOAT, EGlVersion.GL_30),
FLOAT(GL11C.GL_FLOAT, EGlVersion.GL_11),
UNSIGNED_BYTE(GL11C.GL_UNSIGNED_BYTE, EGlVersion.GL_11),
UNSIGNED_BYTE_3_3_2(GL12C.GL_UNSIGNED_BYTE_3_3_2, EGlVersion.GL_12),
UNSIGNED_BYTE_2_3_3_REV(GL12C.GL_UNSIGNED_BYTE_2_3_3_REV, EGlVersion.GL_12),
UNSIGNED_SHORT(GL11C.GL_UNSIGNED_SHORT, EGlVersion.GL_11),
UNSIGNED_SHORT_5_6_5(GL12C.GL_UNSIGNED_SHORT_5_6_5, EGlVersion.GL_12),
UNSIGNED_SHORT_5_6_5_REV(GL12C.GL_UNSIGNED_SHORT_5_6_5_REV, EGlVersion.GL_12),
UNSIGNED_SHORT_4_4_4_4(GL12C.GL_UNSIGNED_SHORT_4_4_4_4, EGlVersion.GL_12),
UNSIGNED_SHORT_4_4_4_4_REV(GL12C.GL_UNSIGNED_SHORT_4_4_4_4_REV, EGlVersion.GL_12),
UNSIGNED_SHORT_5_5_5_1(GL12C.GL_UNSIGNED_SHORT_5_5_5_1, EGlVersion.GL_12),
UNSIGNED_SHORT_1_5_5_5_REV(GL12C.GL_UNSIGNED_SHORT_1_5_5_5_REV, EGlVersion.GL_12),
UNSIGNED_INT(GL11C.GL_UNSIGNED_INT, EGlVersion.GL_11),
UNSIGNED_INT_8_8_8_8(GL12C.GL_UNSIGNED_INT_8_8_8_8, EGlVersion.GL_12),
UNSIGNED_INT_8_8_8_8_REV(GL12C.GL_UNSIGNED_INT_8_8_8_8_REV, EGlVersion.GL_12),
UNSIGNED_INT_10_10_10_2(GL12C.GL_UNSIGNED_INT_10_10_10_2, EGlVersion.GL_12),
UNSIGNED_INT_2_10_10_10_REV(GL12C.GL_UNSIGNED_INT_2_10_10_10_REV, EGlVersion.GL_12);
private final int glFormat;
private final EGlVersion minimumGlVersion;
EGlDhPixelType(int glFormat, EGlVersion minimumGlVersion)
{
this.glFormat = glFormat;
this.minimumGlVersion = minimumGlVersion;
}
public static Optional<EGlDhPixelType> fromString(String name)
{
try
{
return Optional.of(EGlDhPixelType.valueOf(name.toUpperCase(Locale.US)));
}
catch (IllegalArgumentException e)
{
return Optional.empty();
}
}
public int getGlFormat() { return glFormat; }
public EGlVersion getMinimumGlVersion() { return minimumGlVersion; }
}
@@ -1,183 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import org.joml.Vector2i;
import org.lwjgl.opengl.GL11C;
import org.lwjgl.opengl.GL13C;
import org.lwjgl.opengl.GL43C;
import java.nio.ByteBuffer;
public class GlDhColorTexture
{
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private final EGlDhInternalTextureFormat internalFormat;
private final EGlDhPixelFormat format;
private final EGlDhPixelType type;
private int width;
private int height;
private boolean isValid;
/** AKA, the OpenGL name of this texture */
private final int id;
private static final ByteBuffer NULL_BUFFER = null;
//=============//
// constructor //
//=============//
public GlDhColorTexture(Builder builder)
{
this.isValid = true;
this.internalFormat = builder.internalFormat;
this.format = builder.format;
this.type = builder.type;
this.width = builder.width;
this.height = builder.height;
this.id = GL43C.glGenTextures();
boolean isPixelFormatInteger = builder.internalFormat.getPixelFormat().isInteger();
this.setupTexture(this.id, builder.width, builder.height, !isPixelFormatInteger); // this binds the texture
// Clean up after ourselves
// This is strictly defensive to ensure that other buggy code doesn't tamper with our textures
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, 0);
}
//=========//
// methods //
//=========//
private void setupTexture(int id, int width, int height, boolean allowsLinear)
{
this.resizeTexture(id, width, height);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, allowsLinear ? GL11C.GL_LINEAR : GL11C.GL_NEAREST);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, allowsLinear ? GL11C.GL_LINEAR : GL11C.GL_NEAREST);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_S, GL13C.GL_CLAMP_TO_EDGE);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_T, GL13C.GL_CLAMP_TO_EDGE);
// disable mip-mapping since DH is just going to draw straight to the screen
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
}
private void resizeTexture(int texture, int width, int height)
{
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, texture);
GL43C.glTexImage2D(GL11C.GL_TEXTURE_2D, 0, this.internalFormat.getGlFormat(), width, height, 0, this.format.getGlFormat(), this.type.getGlFormat(), NULL_BUFFER);
}
void resize(Vector2i textureScaleOverride) { this.resize(textureScaleOverride.x, textureScaleOverride.y); }
// Package private, call CompositeRenderTargets#resizeIfNeeded instead.
public void resize(int width, int height)
{
this.throwIfInvalid();
this.width = width;
this.height = height;
this.resizeTexture(this.id, width, height);
}
public EGlDhInternalTextureFormat getInternalFormat() { return this.internalFormat; }
public int getTextureId()
{
this.throwIfInvalid();
return this.id;
}
public int getWidth() { return this.width; }
public int getHeight() { return this.height; }
public void destroy()
{
this.throwIfInvalid();
this.isValid = false;
GLMC.glDeleteTextures(this.id);
}
/** @throws IllegalStateException if the texture isn't valid */
private void throwIfInvalid()
{
if (!this.isValid)
{
throw new IllegalStateException("Attempted to use a deleted composite render target");
}
}
public static Builder builder() { return new Builder(); }
//================//
// helper classes //
//================//
public static class Builder
{
private EGlDhInternalTextureFormat internalFormat = EGlDhInternalTextureFormat.RGBA8;
private int width = 0;
private int height = 0;
private EGlDhPixelFormat format = EGlDhPixelFormat.RGBA;
private EGlDhPixelType type = EGlDhPixelType.UNSIGNED_BYTE;
private Builder()
{
// No-op
}
public Builder setInternalFormat(EGlDhInternalTextureFormat format)
{
this.internalFormat = format;
return this;
}
public Builder setDimensions(int width, int height)
{
if (width <= 0)
{
throw new IllegalArgumentException("Width must be greater than zero");
}
if (height <= 0)
{
throw new IllegalArgumentException("Height must be greater than zero");
}
this.width = width;
this.height = height;
return this;
}
public Builder setPixelFormat(EGlDhPixelFormat pixelFormat)
{
this.format = pixelFormat;
return this;
}
public Builder setPixelType(EGlDhPixelType pixelType)
{
this.type = pixelType;
return this;
}
public GlDhColorTexture build() { return new GlDhColorTexture(this); }
}
}
@@ -1,62 +0,0 @@
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import org.lwjgl.opengl.GL11C;
import org.lwjgl.opengl.GL13C;
import org.lwjgl.opengl.GL43C;
import java.nio.ByteBuffer;
public class GlDhDepthTexture
{
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private int id;
public GlDhDepthTexture(int width, int height, EGlDhDepthBufferFormat format)
{
this.id = GL43C.glGenTextures();
this.resize(width, height, format);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, GL11C.GL_NEAREST);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, GL11C.GL_NEAREST);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_S, GL13C.GL_CLAMP_TO_EDGE);
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_T, GL13C.GL_CLAMP_TO_EDGE);
// disable mip-mapping since DH is just going to draw straight to the screen
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, 0);
}
// For internal use by Iris for copying data. Do not use this in DH.
public GlDhDepthTexture(int id) { this.id = id; }
public void resize(int width, int height, EGlDhDepthBufferFormat format)
{
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, this.getTextureId());
GL43C.glTexImage2D(GL11C.GL_TEXTURE_2D, 0, format.getGlInternalFormat(), width, height, 0,
format.getGlType(), format.getGlFormat(), (ByteBuffer) null);
}
public int getTextureId()
{
if (this.id == -1)
{
throw new IllegalStateException("Depth texture does not exist!");
}
return this.id;
}
public void destroy()
{
GLMC.glDeleteTextures(this.getTextureId());
this.id = -1;
}
}
@@ -1,92 +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.common.render.openGl.glObject.vertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import org.lwjgl.opengl.GL32;
/**
* Base for binding/unbinding Vertex Attribute objects (VAO's).
*
* @see GlVertexAttributePostGL43
* @see GlVertexAttributePreGL43
*/
public abstract class GlAbstractVertexAttribute
{
/** Stores the handle of the AbstractVertexAttribute. */
public final int id;
//==============//
// constructors //
//==============//
// This will bind AbstractVertexAttribute
protected GlAbstractVertexAttribute()
{
this.id = GL32.glGenVertexArrays();
GL32.glBindVertexArray(this.id);
}
public static GlAbstractVertexAttribute create()
{
if (GLProxy.getInstance().vertexAttributeBufferBindingSupported)
{
return new GlVertexAttributePostGL43();
}
else
{
return new GlVertexAttributePreGL43();
}
}
//=========//
// binding //
//=========//
public void bind() { GL32.glBindVertexArray(this.id); }
public void unbind() { GL32.glBindVertexArray(0); }
/** Always remember to always free your resources! */
public void free() { GL32.glDeleteVertexArrays(this.id); }
//==================//
// abstract methods //
//==================//
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
public abstract void bindBufferToAllBindingPoints(int buffer);
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
public abstract void bindBufferToBindingPoint(int buffer, int bindingPoint);
/** Requires both AbstractVertexAttribute to be bound */
public abstract void unbindBuffersFromAllBindingPoint();
/** Requires both AbstractVertexAttribute to be bound */
public abstract void unbindBuffersFromBindingPoint(int bindingPoint);
/** Requires both AbstractVertexAttribute to be bound */
public abstract void setVertexAttribute(int bindingPoint, int attributeIndex, GlVertexPointer attribute);
/** Requires both AbstractVertexAttribute to be bound */
public abstract void completeAndCheck(int expectedStrideSize);
}
@@ -1,155 +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.common.render.openGl.glObject.vertexAttribute;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.lwjgl.opengl.GL43;
/**
* In OpenGL 4.3 and later, Vertex Attribute got a make-over.
* Now it provides support for buffer binding points natively.
* This means that setting up the VAO is just use ONE native call when
* binding to a buffer. <br><br>
*
* Since I no longer need to implement binding points, I also no
* longer needs to keep track of Pointers.
*/
public final class GlVertexAttributePostGL43 extends GlAbstractVertexAttribute
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
int numberOfBindingPoints = 0;
int strideSize = 0;
//=============//
// constructor //
//=============//
/** This will bind the {@link GlAbstractVertexAttribute} */
public GlVertexAttributePostGL43()
{
super(); // also bind AbstractVertexAttribute
}
//=========//
// binding //
//=========//
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
public void bindBufferToAllBindingPoints(int buffer)
{
for (int i = 0; i < this.numberOfBindingPoints; i++)
{
GL43.glBindVertexBuffer(i, buffer, 0, this.strideSize);
}
}
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
public void bindBufferToBindingPoint(int buffer, int bindingPoint)
{
GL43.glBindVertexBuffer(bindingPoint, buffer, 0, this.strideSize);
}
//===========//
// unbinding //
//===========//
/** Requires AbstractVertexAttribute to be bound */
@Override
public void unbindBuffersFromAllBindingPoint()
{
for (int i = 0; i < this.numberOfBindingPoints; i++)
{
GL43.glBindVertexBuffer(i, 0, 0, 0);
}
}
/** Requires AbstractVertexAttribute to be bound */
@Override
public void unbindBuffersFromBindingPoint(int bindingPoint)
{
GL43.glBindVertexBuffer(bindingPoint, 0, 0, 0);
}
//==========================//
// manual attribute setting //
//==========================//
/** Requires AbstractVertexAttribute to be bound */
@Override
public void setVertexAttribute(int bindingPoint, int attributeIndex, GlVertexPointer attribute)
{
if (attribute.useInteger)
{
GL43.glVertexAttribIFormat(attributeIndex, attribute.elementCount, attribute.glType, this.strideSize);
}
else
{
GL43.glVertexAttribFormat(attributeIndex, attribute.elementCount, attribute.glType,
attribute.normalized, this.strideSize); // Here strideSize is new attrib offset
}
this.strideSize += attribute.byteSize;
if (this.numberOfBindingPoints <= bindingPoint)
{
this.numberOfBindingPoints = bindingPoint + 1;
}
GL43.glVertexAttribBinding(attributeIndex, bindingPoint);
GL43.glEnableVertexAttribArray(attributeIndex);
}
//============//
// validation //
//============//
/** Requires AbstractVertexAttribute to be bound */
@Override
public void completeAndCheck(int expectedStrideSize)
{
if (this.strideSize != expectedStrideSize)
{
LOGGER.error("Vertex Attribute calculated stride size " + this.strideSize +
" does not match the provided expected stride size " + expectedStrideSize + "!");
throw new IllegalArgumentException("Vertex Attribute Incorrect Format");
}
LOGGER.info("Vertex Attribute (GL43+) completed. It contains " + this.numberOfBindingPoints
+ " binding points and a stride size of " + this.strideSize);
}
}
@@ -1,253 +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.common.render.openGl.glObject.vertexAttribute;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.TreeSet;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.lwjgl.opengl.GL32;
public final class GlVertexAttributePreGL43 extends GlAbstractVertexAttribute
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
.build();
// I tried to use raw arrays as much as possible since those lookups
// happen every frame, and the speed directly affects fps
int strideSize = 0;
int[][] bindingPointsToIndex;
GlVertexPointer[] pointers;
int[] pointersOffset;
TreeMap<Integer, TreeSet<Integer>> bindingPointsToIndexBuilder;
ArrayList<GlVertexPointer> pointersBuilder;
//=============//
// constructor //
//=============//
/** This will bind the {@link GlAbstractVertexAttribute} */
public GlVertexAttributePreGL43()
{
super(); // also bind AbstractVertexAttribute
this.bindingPointsToIndexBuilder = new TreeMap<>();
this.pointersBuilder = new ArrayList<>();
}
//=========//
// binding //
//=========//
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
public void bindBufferToAllBindingPoints(int buffer)
{
for (int i = 0; i < this.pointers.length; i++)
{
GL32.glEnableVertexAttribArray(i);
}
for (int i = 0; i < this.pointers.length; i++)
{
GlVertexPointer pointer = this.pointers[i];
if (pointer == null)
{
continue;
}
if (pointer.useInteger)
{
GL32.glVertexAttribIPointer(i, pointer.elementCount, pointer.glType,
this.strideSize, this.pointersOffset[i]);
}
else
{
GL32.glVertexAttribPointer(i, pointer.elementCount, pointer.glType,
pointer.normalized, this.strideSize, this.pointersOffset[i]);
}
}
}
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
@Override
public void bindBufferToBindingPoint(int buffer, int bindingPoint)
{
int[] bindingPointIndexes = this.bindingPointsToIndex[bindingPoint];
for (int bindingPointIndex : bindingPointIndexes)
{
GL32.glEnableVertexAttribArray(bindingPointIndex);
}
for (int bindingPointIndex : bindingPointIndexes)
{
GlVertexPointer pointer = this.pointers[bindingPointIndex];
if (pointer == null)
{
continue;
}
if (pointer.useInteger)
{
GL32.glVertexAttribIPointer(bindingPointIndex, pointer.elementCount, pointer.glType,
this.strideSize, this.pointersOffset[bindingPointIndex]);
}
else
{
GL32.glVertexAttribPointer(bindingPointIndex, pointer.elementCount, pointer.glType,
pointer.normalized, this.strideSize, this.pointersOffset[bindingPointIndex]);
}
}
}
//===========//
// unbinding //
//===========//
/** Requires AbstractVertexAttribute to be bound */
@Override
public void unbindBuffersFromAllBindingPoint()
{
for (int i = 0; i < this.pointers.length; i++)
{
GL32.glDisableVertexAttribArray(i);
}
}
/** Requires AbstractVertexAttribute to be bound */
@Override
public void unbindBuffersFromBindingPoint(int bindingPoint)
{
int[] bindingPointIndexes = this.bindingPointsToIndex[bindingPoint];
for (int bindingPointIndex : bindingPointIndexes)
{
GL32.glDisableVertexAttribArray(bindingPointIndex);
}
}
//==========================//
// manual attribute setting //
//==========================//
/** Requires AbstractVertexAttribute to be bound */
@Override
public void setVertexAttribute(int bindingPoint, int attributeIndex, GlVertexPointer attribute)
{
TreeSet<Integer> intArray = this.bindingPointsToIndexBuilder.computeIfAbsent(bindingPoint, k -> new TreeSet<>());
intArray.add(attributeIndex);
while (this.pointersBuilder.size() <= attributeIndex)
{
// This is dumb, but ArrayList doesn't have a resize, And this code
// should only be run when it's building the Vertex Attribute anyway.
this.pointersBuilder.add(null);
}
this.pointersBuilder.set(attributeIndex, attribute);
}
//============//
// validation //
//============//
/** Requires AbstractVertexAttribute to be bound */
@Override
public void completeAndCheck(int expectedStrideSize)
{
int maxBindPointNumber = this.bindingPointsToIndexBuilder.lastKey();
this.bindingPointsToIndex = new int[maxBindPointNumber + 1][];
this.bindingPointsToIndexBuilder.forEach((Integer i, TreeSet<Integer> set) ->
{
this.bindingPointsToIndex[i] = new int[set.size()];
Iterator<Integer> iter = set.iterator();
for (int j = 0; j < set.size(); j++)
{
this.bindingPointsToIndex[i][j] = iter.next();
}
});
this.pointers = this.pointersBuilder.toArray(new GlVertexPointer[this.pointersBuilder.size()]);
this.pointersOffset = new int[this.pointers.length];
this.pointersBuilder = null; // Release the builder
this.bindingPointsToIndexBuilder = null; // Release the builder
// Check if all pointers are valid
int currentOffset = 0;
for (int i = 0; i < this.pointers.length; i++)
{
GlVertexPointer pointer = this.pointers[i];
if (pointer == null)
{
LOGGER.warn("Vertex Attribute index " + i + " is not set! No index should be skipped normally!");
continue;
}
this.pointersOffset[i] = currentOffset;
currentOffset += pointer.byteSize;
}
if (currentOffset != expectedStrideSize)
{
LOGGER.error("Vertex Attribute calculated stride size " + currentOffset +
" does not match the provided expected stride size " + expectedStrideSize + "!");
throw new IllegalArgumentException("Vertex Attribute Incorrect Format");
}
this.strideSize = currentOffset;
LOGGER.info("Vertex Attribute (pre GL43) completed.");
// Debug logging
LOGGER.debug("AttributeIndex: ElementCount, glType, normalized, strideSize, offset");
for (int i = 0; i < this.pointers.length; i++)
{
GlVertexPointer pointer = this.pointers[i];
if (pointer == null)
{
LOGGER.debug(i + ": Null!!!!");
}
else
{
LOGGER.debug(i + ": " + pointer.elementCount + ", " +
pointer.glType + ", " + pointer.normalized + ", " + this.strideSize + ", " + this.pointersOffset[i]);
}
}
}
}
@@ -1,72 +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.common.render.openGl.glObject.vertexAttribute;
import com.seibel.distanthorizons.coreapi.util.MathUtil;
import org.lwjgl.opengl.GL32;
public final class GlVertexPointer
{
public final int elementCount;
public final int glType;
public final boolean normalized;
public final int byteSize;
public final boolean useInteger;
// basic constructors //
public GlVertexPointer(int elementCount, int glType, boolean normalized, int byteSize, boolean useInteger)
{
this.elementCount = elementCount;
this.glType = glType;
this.normalized = normalized;
this.byteSize = byteSize;
this.useInteger = useInteger;
}
public GlVertexPointer(int elementCount, int glType, boolean normalized, int byteSize)
{
this(elementCount, glType, normalized, byteSize, false);
}
private static int _align(int bytes) { return MathUtil.ceilDiv(bytes, 4) * 4; }
// named constructors //
public static GlVertexPointer addFloatPointer(boolean normalized) { return new GlVertexPointer(1, GL32.GL_FLOAT, normalized, Float.BYTES); }
public static GlVertexPointer addVec2Pointer(boolean normalized) { return new GlVertexPointer(2, GL32.GL_FLOAT, normalized, Float.BYTES * 2); }
public static GlVertexPointer addVec3Pointer(boolean normalized) { return new GlVertexPointer(3, GL32.GL_FLOAT, normalized, Float.BYTES * 3); }
public static GlVertexPointer addVec4Pointer(boolean normalized) { return new GlVertexPointer(4, GL32.GL_FLOAT, normalized, Float.BYTES * 4); }
/** Always aligned to 4 bytes */
public static GlVertexPointer addUnsignedBytePointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(1, GL32.GL_UNSIGNED_BYTE, normalized, 4, useInteger); }
/** aligned to 4 bytes */
public static GlVertexPointer addUnsignedBytesPointer(int elementCount, boolean normalized, boolean useInteger)
{ return new GlVertexPointer(elementCount, GL32.GL_UNSIGNED_BYTE, normalized, _align(elementCount), useInteger); }
public static GlVertexPointer addUnsignedShortsPointer(int elementCount, boolean normalized, boolean useInteger)
{ return new GlVertexPointer(elementCount, GL32.GL_UNSIGNED_SHORT, normalized, _align(elementCount * 2), useInteger); }
public static GlVertexPointer addShortsPointer(int elementCount, boolean normalized, boolean useInteger) { return new GlVertexPointer(elementCount, GL32.GL_SHORT, normalized, _align(elementCount * 2), useInteger); }
public static GlVertexPointer addIntPointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(1, GL32.GL_INT, normalized, 4, useInteger); }
public static GlVertexPointer addIVec2Pointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(2, GL32.GL_INT, normalized, 8, useInteger); }
public static GlVertexPointer addIVec3Pointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(3, GL32.GL_INT, normalized, 12, useInteger); }
public static GlVertexPointer addIVec4Pointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(4, GL32.GL_INT, normalized, 16, useInteger); }
}
@@ -1,116 +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.common.render.openGl.postProcessing;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
/**
* Renders a full-screen textured quad to the screen.
* Used in composite / deferred rendering (IE fog).
*/
public class GlScreenQuad
{
public static GlScreenQuad INSTANCE = new GlScreenQuad();
private static final float[] BOX_VERTICES = {
-1, -1,
1, -1,
1, 1,
-1, -1,
1, 1,
-1, 1,
};
private GLVertexBuffer boxBuffer;
private GlAbstractVertexAttribute va;
private boolean init = false;
//=============//
// constructor //
//=============//
//region
private GlScreenQuad() { }
public void init()
{
if (this.init) return;
this.init = true;
this.va = GlAbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec2Pointer(false));
this.va.completeAndCheck(Float.BYTES * 2);
// Framebuffer
this.createBuffer();
}
private void createBuffer()
{
ByteBuffer buffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
buffer.asFloatBuffer().put(BOX_VERTICES);
buffer.rewind();
this.boxBuffer = new GLVertexBuffer(false);
this.boxBuffer.bind();
this.boxBuffer.uploadBuffer(buffer, BOX_VERTICES.length, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
MemoryUtil.memFree(buffer);
}
//endregion
//===========//
// rendering //
//===========//
//region
public void render()
{
this.init();
this.boxBuffer.bind();
this.va.bind();
this.va.bindBufferToAllBindingPoints(this.boxBuffer.getId());
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
}
//endregion
}
@@ -1,190 +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.common.render.openGl.postProcessing.apply;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.opengl.GL32;
/**
* Copies {@link com.seibel.distanthorizons.core.render.renderer.LodRenderer}'s currently active color and depth texture to Minecraft's framebuffer.
*/
public class GlDhApplyShader extends GlAbstractShaderRenderer
{
public static GlDhApplyShader INSTANCE = new GlDhApplyShader();
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
// uniforms
public int gDhColorTextureUniform;
public int gDepthMapUniform;
//=======//
// setup //
//=======//
//region
private GlDhApplyShader() { }
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/shared/gl/apply.frag",
"vPosition"
);
// uniform setup
this.gDhColorTextureUniform = this.shader.getUniformLocation("gDhColorTexture");
this.gDepthMapUniform = this.shader.getUniformLocation("gDhDepthTexture");
}
//endregion
//========//
// render //
//========//
//region
@Override
protected void onRender()
{
if (MC_RENDER.mcRendersToFrameBuffer())
{
this.renderToFrameBuffer();
}
else
{
this.renderToMcTexture();
}
}
private void renderToFrameBuffer()
{
int targetFrameBuffer = MC_RENDER.getTargetFramebuffer();
if (targetFrameBuffer == -1)
{
return;
}
try (GLState state = new GLState())
{
GLMC.disableDepthTest();
// blending isn't needed, we're manually merging the MC and DH textures
// Note: this prevents the sun/moon and stars from rendering through transparent LODs,
// 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.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveColorTextureId());
GL32.glUniform1i(this.gDhColorTextureUniform, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
GL32.glUniform1i(this.gDepthMapUniform, 1);
// Copy to MC's framebuffer
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, targetFrameBuffer);
GlScreenQuad.INSTANCE.render();
}
// everything's been restored, except at this point the MC framebuffer should now be used instead
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, targetFrameBuffer);
}
private void renderToMcTexture()
{
int targetColorTextureId = MC_RENDER.getColorTextureId();
if (targetColorTextureId == -1)
{
return;
}
int dhFrameBufferId = GlDhMetaRenderer.INSTANCE.getActiveFramebufferId();
if (dhFrameBufferId == -1)
{
return;
}
int mcFrameBufferId = MC_RENDER.getTargetFramebuffer();
if (mcFrameBufferId == -1)
{
return;
}
try (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,
// but it also resolves some other issues, so it's likely not an issue
GLMC.disableBlend();
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveColorTextureId());
GL32.glUniform1i(this.gDhColorTextureUniform, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.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);
GlScreenQuad.INSTANCE.render();
}
// everything's been restored, except at this point the MC framebuffer should now be used instead
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, mcFrameBufferId);
}
//endregion
}
@@ -1,116 +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.common.render.openGl.postProcessing.fade;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.render.RenderParams;
import org.lwjgl.opengl.GL32;
/**
* Draws the Fade texture onto Minecraft's FrameBuffer. <br><br>
*
* See Also: <br>
* {@link GlVanillaFadeRenderer} - Parent to this shader. <br>
* {@link GlDhVanillaFadeShader} - draws the Fade texture. <br>
*/
public class GlDhFarFadeApplyShader extends GlAbstractShaderRenderer
{
public static GlDhFarFadeApplyShader INSTANCE = new GlDhFarFadeApplyShader();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int fadeTexture;
public int readFramebuffer;
public int drawFramebuffer;
// uniforms
public int uFadeColorTextureUniform = -1;
//=============//
// constructor //
//=============//
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/fade/gl/apply.frag",
"vPosition"
);
// uniform setup
this.uFadeColorTextureUniform = this.shader.getUniformLocation("uFadeColorTextureUniform");
}
//=============//
// render prep //
//=============//
@Override
protected void onApplyUniforms(RenderParams renderParams)
{
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(this.fadeTexture);
GL32.glUniform1i(this.uFadeColorTextureUniform, 0);
}
//========//
// render //
//========//
@Override
protected void onRender()
{
GLMC.disableBlend();
// Depth testing must be disabled otherwise this application shader won't apply anything.
// setting this isn't necessary in vanilla, but some mods may change this, requiring it to be set manually,
// it should be automatically restored after rendering is complete.
GLMC.disableDepthTest();
// apply the rendered Fade to Minecraft's framebuffer
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, this.readFramebuffer);
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, this.drawFramebuffer);
GlScreenQuad.INSTANCE.render();
GLMC.enableDepthTest();
}
}
@@ -1,165 +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.common.render.openGl.postProcessing.fade;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL43C;
import java.nio.ByteBuffer;
/**
* Handles fading MC and DH together via {@link GlDhFarFadeShader} and {@link GlDhFarFadeApplyShader}. <br><br>
*
* {@link GlDhFarFadeShader} - draws the Fade to a texture. <br>
* {@link GlDhFarFadeApplyShader} - draws the Fade texture to DH's framebuffer. <br>
*/
public class GlDhFarFadeRenderer implements IDhFarFadeRenderer
{
public static GlDhFarFadeRenderer INSTANCE = new GlDhFarFadeRenderer();
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private boolean init = false;
private int width = -1;
private int height = -1;
private int fadeFramebuffer = -1;
private int fadeTexture = -1;
//=============//
// constructor //
//=============//
//region
private GlDhFarFadeRenderer() { }
public void init()
{
if (this.init) return;
this.init = true;
GlDhFarFadeShader.INSTANCE.init();
GlDhFarFadeApplyShader.INSTANCE.init();
}
private void createFramebuffer(int width, int height)
{
if (this.fadeFramebuffer != -1)
{
GL32.glDeleteFramebuffers(this.fadeFramebuffer);
this.fadeFramebuffer = -1;
}
this.fadeFramebuffer = GL32.glGenFramebuffers();
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer);
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);
// disable mip-mapping since DH is just going to draw straight to the screen
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
}
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0);
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
try
{
//profiler.push("Fade Generate");
this.init();
// resize the framebuffer if necessary
int width = MC_RENDER.getTargetFramebufferViewportWidth();
int height = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
this.createFramebuffer(width, height);
}
GlDhFarFadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer;
GlDhFarFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix);
GlDhFarFadeShader.INSTANCE.render(renderParams);
//profiler.popPush("Fade Apply");
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhFarFadeShader.INSTANCE.frameBuffer;
GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = GlDhMetaRenderer.INSTANCE.getActiveFramebufferId();
GlDhFarFadeApplyShader.INSTANCE.render(renderParams);
}
catch (Exception e)
{
LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e);
}
finally
{
//profiler.pop();
}
}
//emdregion
}
@@ -1,167 +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.common.render.openGl.postProcessing.fade;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL32;
public class GlDhFarFadeShader extends GlAbstractShaderRenderer
{
public static GlDhFarFadeShader INSTANCE = new GlDhFarFadeShader();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int frameBuffer = -1;
private Mat4f inverseDhMvmProjMatrix;
// Uniforms
/** Inverted Model View Projection matrix */
public int uDhInvMvmProj = -1;
public int uDhDepthTexture = -1;
public int uMcColorTexture = -1;
public int uDhColorTexture = -1;
public int uStartFadeBlockDistance = -1;
public int uEndFadeBlockDistance = -1;
//=============//
// constructor //
//=============//
public GlDhFarFadeShader() { }
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/fade/gl/dhFade.frag",
"vPosition"
);
// all uniforms should be tryGet...
// because disabling fade can cause the GLSL to optimize out most (if not all) uniforms
// near fade
this.uDhInvMvmProj = this.shader.tryGetUniformLocation("uDhInvMvmProj");
this.uDhDepthTexture = this.shader.tryGetUniformLocation("uDhDepthTexture");
this.uMcColorTexture = this.shader.tryGetUniformLocation("uMcColorTexture");
this.uDhColorTexture = this.shader.tryGetUniformLocation("uDhColorTexture");
this.uStartFadeBlockDistance = this.shader.tryGetUniformLocation("uStartFadeBlockDistance");
this.uEndFadeBlockDistance = this.shader.tryGetUniformLocation("uEndFadeBlockDistance");
}
//=============//
// render prep //
//=============//
@Override
protected void onApplyUniforms(RenderParams renderParams)
{
this.shader.setUniform(this.uDhInvMvmProj, this.inverseDhMvmProjMatrix);
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
float fadeStartDistance = dhFarClipDistance * 0.5f;
float fadeEndDistance = dhFarClipDistance * 0.9f;
this.shader.setUniform(this.uStartFadeBlockDistance, fadeStartDistance);
this.shader.setUniform(this.uEndFadeBlockDistance, fadeEndDistance);
}
public void setProjectionMatrix(DhApiMat4f mcModelViewMatrix, DhApiMat4f mcProjectionMatrix)
{
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(mcModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
this.inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
}
//========//
// render //
//========//
@Override
protected void onRender()
{
int depthTextureId = GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId();
int colorTextureId = GlDhMetaRenderer.INSTANCE.getActiveColorTextureId();
if (depthTextureId == -1
|| colorTextureId == -1)
{
// the renderer is currently being re-built and/or inactive,
// we don't need to/can't render fading
return;
}
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
GLMC.disableScissorTest();
GLMC.disableDepthTest();
GLMC.disableBlend();
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(depthTextureId);
GL32.glUniform1i(this.uDhDepthTexture, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(MC_RENDER.getColorTextureId());
GL32.glUniform1i(this.uMcColorTexture, 1);
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
GLMC.glBindTexture(colorTextureId);
GL32.glUniform1i(this.uDhColorTexture, 2);
GlScreenQuad.INSTANCE.render();
}
}
@@ -1,211 +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.common.render.openGl.postProcessing.fade;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL32;
public class GlDhVanillaFadeShader extends GlAbstractShaderRenderer
{
public static GlDhVanillaFadeShader INSTANCE = new GlDhVanillaFadeShader();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int frameBuffer = -1;
private Mat4f inverseMcMvmProjMatrix;
private Mat4f inverseDhMvmProjMatrix;
private float levelMaxHeight;
// Uniforms
public int uMcDepthTexture = -1;
public int uDhDepthTexture = -1;
public int uCombinedMcDhColorTexture = -1;
public int uDhColorTexture = -1;
/** Inverted Model View Projection matrix */
public int uDhInvMvmProj = -1;
public int uMcInvMvmProj = -1;
public int uStartFadeBlockDistance = -1;
public int uEndFadeBlockDistance = -1;
public int uMaxLevelHeight = -1;
public int uOnlyRenderLods = -1;
//=============//
// constructor //
//=============//
//region
public GlDhVanillaFadeShader() { }
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/fade/gl/vanillaFade.frag",
"vPosition"
);
// all uniforms should be tryGet...
// because disabling fade can cause the GLSL to optimize out most (if not all) uniforms
// near fade
this.uDhInvMvmProj = this.shader.tryGetUniformLocation("uDhInvMvmProj");
this.uMcInvMvmProj = this.shader.tryGetUniformLocation("uMcInvMvmProj");
this.uMcDepthTexture = this.shader.tryGetUniformLocation("uMcDepthTexture");
this.uDhDepthTexture = this.shader.tryGetUniformLocation("uDhDepthTexture");
this.uCombinedMcDhColorTexture = this.shader.tryGetUniformLocation("uCombinedMcDhColorTexture");
this.uDhColorTexture = this.shader.tryGetUniformLocation("uDhColorTexture");
this.uStartFadeBlockDistance = this.shader.tryGetUniformLocation("uStartFadeBlockDistance");
this.uEndFadeBlockDistance = this.shader.tryGetUniformLocation("uEndFadeBlockDistance");
this.uMaxLevelHeight = this.shader.tryGetUniformLocation("uMaxLevelHeight");
this.uOnlyRenderLods = this.shader.tryGetUniformLocation("uOnlyRenderLods");
}
//endregion
//=============//
// render prep //
//=============//
//region
@Override
protected void onApplyUniforms(RenderParams renderParams)
{
this.shader.setUniform(this.uMcInvMvmProj, this.inverseMcMvmProjMatrix);
this.shader.setUniform(this.uDhInvMvmProj, this.inverseDhMvmProjMatrix);
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
// this added value prevents the near clip plane and discard circle from touching, which looks bad
dhNearClipDistance += 16f;
// measured in blocks
// these multipliers in James' tests should provide a fairly smooth transition
// without having underdraw issues
float fadeStartDistance = dhNearClipDistance * 1.5f;
float fadeEndDistance = dhNearClipDistance * 1.9f;
this.shader.setUniform(this.uStartFadeBlockDistance, fadeStartDistance);
this.shader.setUniform(this.uEndFadeBlockDistance, fadeEndDistance);
this.shader.setUniform(this.uMaxLevelHeight, this.levelMaxHeight);
this.shader.setUniform(this.uOnlyRenderLods, Config.Client.Advanced.Debugging.lodOnlyMode.get());
}
public void setProjectionMatrix(DhApiMat4f mcModelViewMatrix, DhApiMat4f mcProjectionMatrix)
{
Mat4f inverseMcModelViewProjectionMatrix = new Mat4f(mcProjectionMatrix);
inverseMcModelViewProjectionMatrix.multiply(mcModelViewMatrix);
inverseMcModelViewProjectionMatrix.invert();
this.inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(mcProjectionMatrix);
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(mcModelViewMatrix);
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
inverseDhModelViewProjectionMatrix.invert();
this.inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
}
public void setLevelMaxHeight(int levelMaxHeight) { this.levelMaxHeight = levelMaxHeight; }
//endregion
//========//
// render //
//========//
//region
@Override
protected void onRender()
{
int depthTextureId = GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId();
int colorTextureId = GlDhMetaRenderer.INSTANCE.getActiveColorTextureId();
if (depthTextureId == -1
|| colorTextureId == -1)
{
// the renderer is currently being re-built and/or inactive,
// we don't need to/can't render fading
return;
}
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
GLMC.disableScissorTest();
GLMC.disableDepthTest();
GLMC.disableBlend();
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(MC_RENDER.getDepthTextureId());
GL32.glUniform1i(this.uMcDepthTexture, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(depthTextureId);
GL32.glUniform1i(this.uDhDepthTexture, 1);
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
GLMC.glBindTexture(MC_RENDER.getColorTextureId());
GL32.glUniform1i(this.uCombinedMcDhColorTexture, 2);
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
GLMC.glBindTexture(colorTextureId);
GL32.glUniform1i(this.uDhColorTexture, 3);
GlScreenQuad.INSTANCE.render();
}
//endregion
}
@@ -1,203 +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.common.render.openGl.postProcessing.fade;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
/**
* Handles fading MC and DH together via {@link GlDhVanillaFadeShader} and {@link GlDhFarFadeApplyShader}. <br><br>
*
* {@link GlDhVanillaFadeShader} - draws the Fade to a texture. <br>
* {@link GlDhFarFadeApplyShader} - draws the Fade texture to MC's FrameBuffer. <br>
*/
public class GlVanillaFadeRenderer implements IDhVanillaFadeRenderer
{
public static GlVanillaFadeRenderer INSTANCE = new GlVanillaFadeRenderer();
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private boolean init = false;
private int width = -1;
private int height = -1;
private int fadeFramebuffer = -1;
private int fadeTexture = -1;
//=============//
// constructor //
//=============//
//region
private GlVanillaFadeRenderer() { }
public void init()
{
if (this.init) return;
this.init = true;
GlDhVanillaFadeShader.INSTANCE.init();
GlDhFarFadeApplyShader.INSTANCE.init();
}
private void createFramebuffer(int width, int height)
{
if (this.fadeFramebuffer != -1)
{
GL32.glDeleteFramebuffers(this.fadeFramebuffer);
this.fadeFramebuffer = -1;
}
this.fadeFramebuffer = GL32.glGenFramebuffers();
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer);
// 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);
}
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
int depthTextureId = GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId();
if (depthTextureId == -1)
{
// the renderer hasn't been set up yet
// trying to render fading may cause GL errors
return;
}
IProfilerWrapper profiler = MC_CLIENT.getProfiler();
profiler.pop(); // get out of "terrain"
profiler.push("DH-Vanilla Fade");
try(GLState mcState = new GLState())
{
profiler.push("Vanilla Fade Generate");
this.init();
// resize the framebuffer if necessary
int width = MC_RENDER.getTargetFramebufferViewportWidth();
int height = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
this.createFramebuffer(width, height);
}
GlDhVanillaFadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer;
GlDhVanillaFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix);
GlDhVanillaFadeShader.INSTANCE.setLevelMaxHeight(renderParams.clientLevelWrapper.getMaxHeight());
GlDhVanillaFadeShader.INSTANCE.render(renderParams);
// 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())
{
profiler.popPush("Vanilla Fade Apply");
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhFarFadeShader.INSTANCE.frameBuffer;
GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = MC_RENDER.getTargetFramebuffer();
GlDhFarFadeApplyShader.INSTANCE.render(renderParams);
}
profiler.pop();
}
catch (Exception e)
{
LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e);
}
}
//endregion
//================//
// base overrides //
//================//
//region
public void free()
{
GlDhVanillaFadeShader.INSTANCE.free();
GlDhFarFadeApplyShader.INSTANCE.free();
}
//endregion
}
@@ -1,118 +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.common.render.openGl.postProcessing.fog;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.render.RenderParams;
import org.lwjgl.opengl.GL32;
/**
* Draws the Fog texture onto DH's FrameBuffer. <br><br>
*
* See Also: <br>
* {@link GlDhFogRenderer} - Parent to this shader. <br>
* {@link GlDhFogShader} - draws the Fog texture. <br>
*/
public class GlDhFogApplyShader extends GlAbstractShaderRenderer
{
public static GlDhFogApplyShader INSTANCE = new GlDhFogApplyShader();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int fogTexture;
// uniforms
public int colorTextureUniform;
public int depthTextureUniform;
//=============//
// constructor //
//=============//
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/fog/gl/apply.frag",
"vPosition"
);
// uniform setup
this.colorTextureUniform = this.shader.getUniformLocation("uColorTexture");
this.depthTextureUniform = this.shader.getUniformLocation("uDepthTexture");
}
//=============//
// render prep //
//=============//
@Override
protected void onApplyUniforms(RenderParams renderParams)
{
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(this.fogTexture);
GL32.glUniform1i(this.colorTextureUniform, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
GL32.glUniform1i(this.depthTextureUniform, 1);
}
//========//
// render //
//========//
@Override
protected void onRender()
{
GLMC.enableBlend();
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
// Depth testing must be disabled otherwise this application shader won't apply anything.
// setting this isn't necessary in vanilla, but some mods may change this, requiring it to be set manually,
// it should be automatically restored after rendering is complete.
GLMC.disableDepthTest();
// apply the rendered Fog to DH's framebuffer
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, GlDhFogShader.INSTANCE.frameBuffer);
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, GlDhMetaRenderer.INSTANCE.getActiveFramebufferId());
GlScreenQuad.INSTANCE.render();
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, 0);
}
}
@@ -1,156 +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.common.render.openGl.postProcessing.fog;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFogRenderer;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL43C;
import java.nio.ByteBuffer;
/**
* Handles adding SSAO via {@link GlDhFogShader} and {@link GlDhFogApplyShader}. <br><br>
*
* {@link GlDhFogShader} - draws the Fog to a texture. <br>
* {@link GlDhFogApplyShader} - draws the Fog texture to DH's FrameBuffer. <br>
*/
public class GlDhFogRenderer implements IDhFogRenderer
{
public static GlDhFogRenderer INSTANCE = new GlDhFogRenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private boolean init = false;
private int width = -1;
private int height = -1;
private int fogFramebuffer = -1;
private int fogTexture = -1;
//=============//
// constructor //
//=============//
private GlDhFogRenderer() { }
public void init()
{
if (this.init) return;
this.init = true;
GlDhFogShader.INSTANCE.init();
GlDhFogApplyShader.INSTANCE.init();
}
private void createFramebuffer(int width, int height)
{
if (this.fogFramebuffer != -1)
{
GL32.glDeleteFramebuffers(this.fogFramebuffer);
this.fogFramebuffer = -1;
}
if (this.fogTexture != -1)
{
GLMC.glDeleteTextures(this.fogTexture);
this.fogTexture = -1;
}
this.fogFramebuffer = GL32.glGenFramebuffers();
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fogFramebuffer);
this.fogTexture = GLMC.glGenTextures();
{
GLMC.glBindTexture(this.fogTexture);
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.fogTexture, 0);
// disable mip-mapping since DH is just going to draw straight to the screen
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
}
}
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
// GLState needed in MC 1.16.5 probably due to MC not manually setting each GL state they need before the next rendering step
try (GLState state = new GLState())
{
this.init();
// resize the framebuffer if necessary
int width = MC_RENDER.getTargetFramebufferViewportWidth();
int height = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
this.createFramebuffer(width, height);
}
GlDhFogShader.INSTANCE.frameBuffer = this.fogFramebuffer;
GlDhFogShader.INSTANCE.setProjectionMatrix(renderParams.dhMvmProjMatrix);
GlDhFogShader.INSTANCE.render(renderParams);
GlDhFogApplyShader.INSTANCE.fogTexture = this.fogTexture;
GlDhFogApplyShader.INSTANCE.render(renderParams);
}
}
//endregion
//================//
// base overrides //
//================//
//region
public void free()
{
GlDhFogShader.INSTANCE.free();
GlDhFogApplyShader.INSTANCE.free();
}
//endregion
}
@@ -1,301 +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.common.render.openGl.postProcessing.fog;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL32;
import java.awt.*;
public class GlDhFogShader extends GlAbstractShaderRenderer
{
public static final GlDhFogShader INSTANCE = new GlDhFogShader();
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
public int frameBuffer;
private Mat4f inverseMvmProjMatrix;
//==========//
// Uniforms //
//==========//
//region
public int uDepthMap;
/** Inverted Model View Projection matrix */
public int uInvMvmProj;
// fog uniforms
public int uFogColor;
public int uFogScale;
public int uFogVerticalScale;
public int uFogDebugMode;
public int uFogFalloffType;
// far fog
public int uFarFogStart;
public int uFarFogLength;
public int uFarFogMin;
public int uFarFogRange;
public int uFarFogDensity;
// height fog
public int uHeightFogStart;
public int uHeightFogLength;
public int uHeightFogMin;
public int uHeightFogRange;
public int uHeightFogDensity;
public int uHeightFogEnabled;
public int uHeightFogFalloffType;
public int uHeightBasedOnCamera;
public int uHeightFogBaseHeight;
public int uHeightFogAppliesUp;
public int uHeightFogAppliesDown;
public int uUseSphericalFog;
public int uHeightFogMixingMode;
public int uCameraBlockYPos;
//endregion
//=============//
// constructor //
//=============//
//region
public GlDhFogShader() { }
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/fog/gl/fog.frag",
"vPosition"
);
// all uniforms should be tryGet...
// because disabling fog can cause the GLSL to optimize out most (if not all) uniforms
this.uDepthMap = this.shader.getUniformLocation("uDepthMap");
this.uInvMvmProj = this.shader.getUniformLocation("uInvMvmProj");
// Fog uniforms
this.uFogScale = this.shader.getUniformLocation("uFogScale");
this.uFogVerticalScale = this.shader.getUniformLocation("uFogVerticalScale");
this.uFogColor = this.shader.getUniformLocation("uFogColor");
this.uFogDebugMode = this.shader.getUniformLocation("uFogDebugMode");
this.uFogFalloffType = this.shader.getUniformLocation("uFogFalloffType");
// fog config
this.uFarFogStart = this.shader.getUniformLocation("uFarFogStart");
this.uFarFogLength = this.shader.getUniformLocation("uFarFogLength");
this.uFarFogMin = this.shader.getUniformLocation("uFarFogMin");
this.uFarFogRange = this.shader.getUniformLocation("uFarFogRange");
this.uFarFogDensity = this.shader.getUniformLocation("uFarFogDensity");
// height fog
this.uHeightFogStart = this.shader.getUniformLocation("uHeightFogStart");
this.uHeightFogLength = this.shader.getUniformLocation("uHeightFogLength");
this.uHeightFogMin = this.shader.getUniformLocation("uHeightFogMin");
this.uHeightFogRange = this.shader.getUniformLocation("uHeightFogRange");
this.uHeightFogDensity = this.shader.getUniformLocation("uHeightFogDensity");
this.uHeightFogEnabled = this.shader.getUniformLocation("uHeightFogEnabled");
this.uHeightFogFalloffType = this.shader.getUniformLocation("uHeightFogFalloffType");
this.uHeightBasedOnCamera = this.shader.getUniformLocation("uHeightBasedOnCamera");
this.uHeightFogBaseHeight = this.shader.getUniformLocation("uHeightFogBaseHeight");
this.uHeightFogAppliesUp = this.shader.getUniformLocation("uHeightFogAppliesUp");
this.uHeightFogAppliesDown = this.shader.getUniformLocation("uHeightFogAppliesDown");
this.uUseSphericalFog = this.shader.getUniformLocation("uUseSphericalFog");
this.uHeightFogMixingMode = this.shader.getUniformLocation("uHeightFogMixingMode");
this.uCameraBlockYPos = this.shader.getUniformLocation("uCameraBlockYPos");
}
//endregion
//=============//
// render prep //
//=============//
//region
@Override
protected void onApplyUniforms(RenderParams renderParams)
{
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
if (this.inverseMvmProjMatrix != null)
{
this.shader.setUniform(this.uInvMvmProj, this.inverseMvmProjMatrix);
}
// Fog uniforms
this.shader.setUniform(this.uFogColor, this.getFogColor(renderParams.partialTicks));
this.shader.setUniform(this.uFogScale, 1.f / lodDrawDistance);
this.shader.setUniform(this.uFogVerticalScale, 1.f / MC.getWrappedClientLevel().getMaxHeight());
// only used for debugging
this.shader.setUniform(this.uFogDebugMode, 0); // 1 = render everything with fog color // 7 = use debug rendering
this.shader.setUniform(this.uFogFalloffType, Config.Client.Advanced.Graphics.Fog.farFogFalloff.get().value);
// fog config
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
// override fog if underwater
if (MC_RENDER.isFogStateSpecial())
{
// hide everything behind fog
farFogStart = 0.0f;
farFogEnd = 0.0f;
}
this.shader.setUniform(this.uFarFogStart, farFogStart);
this.shader.setUniform(this.uFarFogLength, farFogEnd - farFogStart);
this.shader.setUniform(this.uFarFogMin, farFogMin);
this.shader.setUniform(this.uFarFogRange, farFogMax - farFogMin);
this.shader.setUniform(this.uFarFogDensity, farFogDensity);
// height config
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
this.shader.setUniform(this.uHeightFogStart, heightFogStart);
this.shader.setUniform(this.uHeightFogLength, heightFogEnd - heightFogStart);
this.shader.setUniform(this.uHeightFogMin, heightFogMin);
this.shader.setUniform(this.uHeightFogRange, heightFogMax - heightFogMin);
this.shader.setUniform(this.uHeightFogDensity, heightFogDensity);
this.shader.setUniform(this.uHeightFogEnabled, heightFogEnabled);
this.shader.setUniform(this.uHeightFogFalloffType, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value);
this.shader.setUniform(this.uHeightFogBaseHeight, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get());
this.shader.setUniform(this.uHeightBasedOnCamera, heightFogCameraDirection.basedOnCamera);
this.shader.setUniform(this.uHeightFogAppliesUp, heightFogCameraDirection.fogAppliesUp);
this.shader.setUniform(this.uHeightFogAppliesDown, heightFogCameraDirection.fogAppliesDown);
this.shader.setUniform(this.uUseSphericalFog, useSphericalFog);
this.shader.setUniform(this.uHeightFogMixingMode, heightFogMixingMode.value);
this.shader.setUniform(this.uCameraBlockYPos, (float)MC_RENDER.getCameraExactPosition().y);
}
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;
}
public void setProjectionMatrix(DhApiMat4f modelViewProjectionMatrix)
{
this.inverseMvmProjMatrix = new Mat4f(modelViewProjectionMatrix);
this.inverseMvmProjMatrix.invert();
}
//endregion
//========//
// render //
//========//
//region
@Override
protected void onRender()
{
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
GLMC.disableScissorTest();
GLMC.disableDepthTest();
GLMC.disableBlend();
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
GL32.glUniform1i(this.uDepthMap, 0);
// this is necessary for MC 1.16 (IE Legacy OpenGL)
// otherwise the framebuffer isn't cleared correctly and the fog smears across the screen
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);
}
GlScreenQuad.INSTANCE.render();
}
//endregion
}
@@ -1,146 +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.common.render.openGl.postProcessing.ssao;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import org.lwjgl.opengl.GL32;
/**
* Draws the SSAO texture onto DH's FrameBuffer. <br><br>
*
* See Also: <br>
* {@link GlDhSSAORenderer} - Parent to this shader. <br>
* {@link GlDhSSAOShader} - draws the SSAO texture. <br>
*/
public class GlDhSSAOApplyShader extends GlAbstractShaderRenderer
{
public static GlDhSSAOApplyShader INSTANCE = new GlDhSSAOApplyShader();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int ssaoTexture;
// uniforms
public int gSSAOMapUniform;
public int gDepthMapUniform;
public int gViewSizeUniform;
public int gBlurRadiusUniform;
public int gNearUniform;
public int gFarUniform;
//=============//
// constructor //
//=============//
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/ssao/gl/apply.frag",
"vPosition"
);
// uniform setup
this.gSSAOMapUniform = this.shader.getUniformLocation("gSSAOMap");
this.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap");
this.gViewSizeUniform = this.shader.tryGetUniformLocation("gViewSize");
this.gBlurRadiusUniform = this.shader.tryGetUniformLocation("gBlurRadius");
this.gNearUniform = this.shader.tryGetUniformLocation("gNear");
this.gFarUniform = this.shader.tryGetUniformLocation("gFar");
}
//=============//
// render prep //
//=============//
@Override
protected void onApplyUniforms(RenderParams renderParams)
{
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
GL32.glUniform1i(this.gDepthMapUniform, 0);
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
GLMC.glBindTexture(this.ssaoTexture);
GL32.glUniform1i(this.gSSAOMapUniform, 1);
GL32.glUniform1i(this.gBlurRadiusUniform, 2);
if (this.gViewSizeUniform >= 0)
{
GL32.glUniform2f(this.gViewSizeUniform,
MC_RENDER.getTargetFramebufferViewportWidth(),
MC_RENDER.getTargetFramebufferViewportHeight());
}
if (this.gNearUniform >= 0)
{
GL32.glUniform1f(this.gNearUniform,
RenderUtil.getNearClipPlaneInBlocks());
}
if (this.gFarUniform >= 0)
{
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
GL32.glUniform1f(this.gFarUniform, farClipPlane);
}
}
//========//
// render //
//========//
@Override
protected void onRender()
{
GLMC.enableBlend();
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GLMC.glBlendFuncSeparate(GL32.GL_ZERO, GL32.GL_SRC_ALPHA, GL32.GL_ZERO, GL32.GL_ONE);
// Depth testing must be disabled otherwise this application shader won't apply anything.
// setting this isn't necessary in vanilla, but some mods may change this, requiring it to be set manually,
// it should be automatically restored after rendering is complete.
GLMC.disableDepthTest();
// apply the rendered SSAO to the LODs
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, GlDhSSAOShader.INSTANCE.frameBuffer);
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, GlDhMetaRenderer.INSTANCE.getActiveFramebufferId());
GlScreenQuad.INSTANCE.render();
}
}
@@ -1,156 +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.common.render.openGl.postProcessing.ssao;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhSsaoRenderer;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL43C;
import java.nio.ByteBuffer;
/**
* Handles adding SSAO via {@link GlDhSSAOShader} and {@link GlDhSSAOApplyShader}. <br><br>
*
* {@link GlDhSSAOShader} - draws the SSAO to a texture. <br>
* {@link GlDhSSAOApplyShader} - draws the SSAO texture to DH's FrameBuffer. <br>
*/
public class GlDhSSAORenderer implements IDhSsaoRenderer
{
public static GlDhSSAORenderer INSTANCE = new GlDhSSAORenderer();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private boolean init = false;
private int width = -1;
private int height = -1;
private int ssaoFramebuffer = -1;
private int ssaoTexture = -1;
//=============//
// constructor //
//=============//
private GlDhSSAORenderer() { }
public void init()
{
if (this.init) return;
this.init = true;
GlDhSSAOShader.INSTANCE.init();
GlDhSSAOApplyShader.INSTANCE.init();
}
private void createFramebuffer(int width, int height)
{
if (this.ssaoFramebuffer != -1)
{
GL32.glDeleteFramebuffers(this.ssaoFramebuffer);
this.ssaoFramebuffer = -1;
}
if (this.ssaoTexture != -1)
{
GLMC.glDeleteTextures(this.ssaoTexture);
this.ssaoTexture = -1;
}
this.ssaoFramebuffer = GL32.glGenFramebuffers();
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
this.ssaoTexture = GLMC.glGenTextures();
{
GLMC.glBindTexture(this.ssaoTexture);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R16F, width, height, 0, GL32.GL_RED, GL32.GL_HALF_FLOAT, (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);
// disable mip-mapping since DH is just going to draw straight to the screen
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
}
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.ssaoTexture, 0);
}
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
try(GLState state = new GLState())
{
this.init();
// resize the framebuffer if necessary
int width = MC_RENDER.getTargetFramebufferViewportWidth();
int height = MC_RENDER.getTargetFramebufferViewportHeight();
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
this.createFramebuffer(width, height);
}
GlDhSSAOShader.INSTANCE.frameBuffer = this.ssaoFramebuffer;
GlDhSSAOShader.INSTANCE.setProjectionMatrix(renderParams.dhProjectionMatrix);
GlDhSSAOShader.INSTANCE.render(renderParams);
GlDhSSAOApplyShader.INSTANCE.ssaoTexture = this.ssaoTexture;
GlDhSSAOApplyShader.INSTANCE.render(renderParams);
}
}
//endregion
//================//
// base overrides //
//================//
//region
public void free()
{
GlDhSSAOShader.INSTANCE.free();
GlDhSSAOApplyShader.INSTANCE.free();
}
//endregion
}
@@ -1,144 +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.common.render.openGl.postProcessing.ssao;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import org.lwjgl.opengl.GL32;
/**
* Draws the SSAO to a texture. <br><br>
*
* See Also: <br>
* {@link GlDhSSAORenderer} - Parent to this shader. <br>
* {@link GlDhSSAOApplyShader} - draws the SSAO texture to DH's FrameBuffer. <br>
*/
public class GlDhSSAOShader extends GlAbstractShaderRenderer
{
public static GlDhSSAOShader INSTANCE = new GlDhSSAOShader();
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public int frameBuffer;
private Mat4f projection;
private Mat4f invertedProjection;
// uniforms
public int uProj;
public int uInvProj;
public int uSampleCount;
public int uRadius;
public int uStrength;
public int uMinLight;
public int uBias;
public int uDepthMap;
public int uFadeDistanceInBlocks;
//=============//
// constructor //
//=============//
@Override
public void onInit()
{
this.shader = new GlShaderProgram(
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
"assets/distanthorizons/shaders/ssao/gl/ao.frag",
"vPosition"
);
// uniform setup
this.uProj = this.shader.getUniformLocation("uProj");
this.uInvProj = this.shader.getUniformLocation("uInvProj");
this.uSampleCount = this.shader.getUniformLocation("uSampleCount");
this.uRadius = this.shader.getUniformLocation("uRadius");
this.uStrength = this.shader.getUniformLocation("uStrength");
this.uMinLight = this.shader.getUniformLocation("uMinLight");
this.uBias = this.shader.getUniformLocation("uBias");
this.uDepthMap = this.shader.getUniformLocation("uDepthMap");
this.uFadeDistanceInBlocks = this.shader.getUniformLocation("uFadeDistanceInBlocks");
}
//=============//
// render prep //
//=============//
public void setProjectionMatrix(DhApiMat4f projectionMatrix)
{
this.projection = new Mat4f(projectionMatrix);
this.invertedProjection = new Mat4f(projectionMatrix);
this.invertedProjection.invert();
}
@Override
protected void onApplyUniforms(RenderParams renderParams)
{
this.shader.setUniform(this.uProj, this.projection);
this.shader.setUniform(this.uInvProj, this.invertedProjection);
this.shader.setUniform(this.uSampleCount, 6);
this.shader.setUniform(this.uRadius, 4.0f);
this.shader.setUniform(this.uStrength, 0.2f);
this.shader.setUniform(this.uMinLight, 0.25f);
this.shader.setUniform(this.uBias, 0.02f);
this.shader.setUniform(this.uFadeDistanceInBlocks, 1_600.0f);
GL32.glUniform1i(this.uDepthMap, 0);
}
//========//
// render //
//========//
@Override
protected void onRender()
{
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
GLMC.disableScissorTest();
GLMC.disableDepthTest();
GLMC.disableBlend();
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
GlScreenQuad.INSTANCE.render();
}
}
@@ -1,146 +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.common.render.openGl.test;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Renders a UV colored quad
* to the center of the screen to confirm DH's
* apply shader is running correctly
*/
public class GlTestTriangleRenderer implements IDhTestTriangleRenderer
{
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
public static final GlTestTriangleRenderer INSTANCE = new GlTestTriangleRenderer();
// Render a square with uv color
private static final float[] VERTICES =
{
// PosX,Y, ColorR,G,B,A
-0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
};
GlShaderProgram basicShader;
GLVertexBuffer vbo;
GlAbstractVertexAttribute va;
boolean init = false;
//=============//
// constructor //
//=============//
//region
private GlTestTriangleRenderer() { }
public void init()
{
if (this.init)
{
return;
}
LOGGER.info("init");
this.init = true;
this.va = GlAbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec2Pointer(false));
// Color
this.va.setVertexAttribute(0, 1, GlVertexPointer.addVec4Pointer(false));
this.va.completeAndCheck(Float.BYTES * 6);
this.basicShader = new GlShaderProgram(
"assets/distanthorizons/shaders/test/gl/vert.vert",
"assets/distanthorizons/shaders/test/gl/frag.frag",
new String[]{"vPosition", "color"});
this.createBuffer();
}
private void createBuffer()
{
ByteBuffer buffer = ByteBuffer.allocateDirect(VERTICES.length * Float.BYTES);
// Fill buffer with vertices.
buffer.order(ByteOrder.nativeOrder());
buffer.asFloatBuffer().put(VERTICES);
buffer.rewind();
this.vbo = new GLVertexBuffer(false);
this.vbo.bind();
this.vbo.uploadBuffer(buffer, 3, EDhApiGpuUploadMethod.DATA, VERTICES.length * Float.BYTES);
}
//endregion
//========//
// render //
//========//
//region
@Override
public void render(RenderParams renderParams)
{
this.init();
this.basicShader.bind();
this.va.bind();
this.vbo.bind();
this.va.bindBufferToAllBindingPoints(this.vbo.getId());
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 3);
GlDhApplyShader.INSTANCE.render(renderParams);
}
//endregion
}
@@ -1,112 +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.common.render.openGl.util;
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL32;
public abstract class GlAbstractShaderRenderer
{
protected static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
protected GlShaderProgram shader;
protected boolean init = false;
//=======//
// setup //
//=======//
//region
protected GlAbstractShaderRenderer() {}
public void init()
{
if (this.init) return;
this.init = true;
this.onInit();
}
//endregion
//==================//
// abstract methods //
//==================//
//region
protected void onInit() {}
protected void onApplyUniforms(RenderParams renderParams) {}
protected void onRender() {}
//endregion
//===========//
// rendering //
//===========//
//region
public void render(RenderParams renderParams)
{
this.init();
this.shader.bind();
this.onApplyUniforms(renderParams);
int width = MC_RENDER.getTargetFramebufferViewportWidth();
int height = MC_RENDER.getTargetFramebufferViewportHeight();
GL32.glViewport(0, 0, width, height);
this.onRender();
this.shader.unbind();
}
//endregion
//================//
// base overrides //
//================//
//region
public void free()
{
if (this.shader != null)
{
this.shader.free();
}
}
// endregion
}
@@ -1,110 +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.common.render.openGl.util.vertexFormat;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
/**
* This is used to represent a single vertex
* stored in GPU memory,
* <p>
* A (almost) exact copy of Minecraft's
* VertexFormat class, several methods
* were commented out since we didn't need them.
*
* @author James Seibel
* @version 12-9-2021
*/
public class GlLodVertexFormat
{
/** the format of data stored in the GPU buffers */
public static final GlLodVertexFormat DH_VERTEX_FORMAT = GlVertexFormats.POSITION_COLOR_BLOCK_LIGHT_SKY_LIGHT_MATERIAL_ID_NORMAL_INDEX;
private final ImmutableList<GlLodVertexFormatElement> elements;
private final IntList offsets = new IntArrayList();
private final int byteSize;
public GlLodVertexFormat(ImmutableList<GlLodVertexFormatElement> elementList)
{
this.elements = elementList;
int i = 0;
for (GlLodVertexFormatElement LodVertexFormatElement : elementList)
{
this.offsets.add(i);
i += LodVertexFormatElement.getByteSize();
}
this.byteSize = i;
}
public int getByteSize()
{
return this.byteSize;
}
public ImmutableList<GlLodVertexFormatElement> getElements()
{
return this.elements;
}
// Forge added method
public int getOffset(int index)
{
return offsets.getInt(index);
}
@Override
public String toString() { return "format: " + this.elements.size() + " elements: " + this.elements.stream().map(Object::toString).collect(Collectors.joining(" ")); }
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
else if (obj != null && this.getClass() == obj.getClass())
{
GlLodVertexFormat vertexFormat = (GlLodVertexFormat) obj;
return this.byteSize == vertexFormat.byteSize && this.elements.equals(vertexFormat.elements);
}
else
{
return false;
}
}
@Override
public int hashCode() { return this.elements.hashCode(); }
}
@@ -1,168 +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.common.render.openGl.util.vertexFormat;
import org.lwjgl.opengl.GL32;
/**
* This object is used to build LodVertexFormats.
* <p>
* A (almost) exact copy of Minecraft's
* VertexFormatElement class. <br>
* A number of things were removed from the original
* object since we didn't need them, specifically "usage".
*
* @author James Seibel
* @version 11-13-2021
*/
public class GlLodVertexFormatElement
{
private final GlLodVertexFormatElement.DataType dataType;
/** James isn't sure what index is for */
private final int index;
private final int count;
private final int byteSize;
private final boolean isPadding;
public GlLodVertexFormatElement(int newIndex, GlLodVertexFormatElement.DataType newType, int newCount, boolean isPadding)
{
this.dataType = newType;
this.index = newIndex;
this.count = newCount;
this.byteSize = newType.getSize() * this.count;
this.isPadding = isPadding;
}
public final boolean getIsPadding()
{
return isPadding;
}
public final GlLodVertexFormatElement.DataType getType()
{
return this.dataType;
}
public final int getIndex()
{
return this.index;
}
public final int getByteSize()
{
return this.byteSize;
}
// added by Forge
public int getElementCount()
{
return count;
}
public enum DataType
{
FLOAT(4, "Float", GL32.GL_FLOAT),
UBYTE(1, "Unsigned Byte", GL32.GL_UNSIGNED_BYTE),
BYTE(1, "Byte", GL32.GL_BYTE),
USHORT(2, "Unsigned Short", GL32.GL_UNSIGNED_SHORT),
SHORT(2, "Short", GL32.GL_SHORT),
UINT(4, "Unsigned Int", GL32.GL_UNSIGNED_INT),
INT(4, "Int", GL32.GL_INT);
private final int size;
private final String name;
private final int glType;
DataType(int sizeInBytes, String newName, int openGlDataType)
{
this.size = sizeInBytes;
this.name = newName;
this.glType = openGlDataType;
}
public int getSize()
{
return this.size;
}
public String getName()
{
return this.name;
}
public int getGlType()
{
return this.glType;
}
}
@Override
public int hashCode()
{
int i = this.dataType.hashCode();
i = 31 * i + this.index;
return 31 * i + this.count;
}
@Override
public String toString()
{
return this.count + "," + this.dataType.getName();
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
else if (obj != null && this.getClass() == obj.getClass())
{
GlLodVertexFormatElement LodVertexFormatElement = (GlLodVertexFormatElement) obj;
if (this.count != LodVertexFormatElement.count)
{
return false;
}
else if (this.index != LodVertexFormatElement.index)
{
return false;
}
else if (this.dataType != LodVertexFormatElement.dataType)
{
return false;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
@@ -1,50 +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.common.render.openGl.util.vertexFormat;
import com.google.common.collect.ImmutableList;
/**
* A (almost) exact copy of MC's
* DefaultVertexFormats class.
*/
public class GlVertexFormats
{
public static final GlLodVertexFormatElement ELEMENT_POSITION = new GlLodVertexFormatElement(3, GlLodVertexFormatElement.DataType.USHORT, 3, false);
public static final GlLodVertexFormatElement ELEMENT_COLOR = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.UBYTE, 4, false);
public static final GlLodVertexFormatElement ELEMENT_BYTE_PADDING = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.BYTE, 1, true);
public static final GlLodVertexFormatElement ELEMENT_LIGHT = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.UBYTE, 1, false);
public static final GlLodVertexFormatElement ELEMENT_IRIS_MATERIAL_INDEX = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.BYTE, 1, false);
public static final GlLodVertexFormatElement ELEMENT_IRIS_NORMAL_INDEX = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.BYTE, 1, false);
public static final GlLodVertexFormat POSITION_COLOR_BLOCK_LIGHT_SKY_LIGHT_MATERIAL_ID_NORMAL_INDEX = new GlLodVertexFormat(ImmutableList.<GlLodVertexFormatElement>builder()
.add(ELEMENT_POSITION)
.add(ELEMENT_BYTE_PADDING)
.add(ELEMENT_LIGHT)
.add(ELEMENT_COLOR)
.add(ELEMENT_IRIS_MATERIAL_INDEX)
.add(ELEMENT_IRIS_NORMAL_INDEX)
.add(ELEMENT_BYTE_PADDING)
.add(ELEMENT_BYTE_PADDING) // padding is to make sure the format is a multiple of 4
.build());
}
@@ -0,0 +1,32 @@
/*
* 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.common.util;
/**
* Added to MC's dynamic textures via mixins
* in order to denote whether a texture is a lightmap or not. <br><br>
*
* If not done any dynamic texture could be used as the lightmap
* which causes some weird rendering bugs.
*/
public interface ILightTextureMarker
{
void markLightTexture();
}
@@ -19,19 +19,12 @@
package com.seibel.distanthorizons.common.wrappers;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderObjectFactory;
import com.seibel.distanthorizons.common.render.blaze.BlazeDhRenderApiDefinition;
import com.seibel.distanthorizons.common.render.openGl.GlDhRenderApiDefinition;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI;
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
@@ -40,9 +33,9 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
/**
* Binds all necessary dependencies, so we
@@ -56,9 +49,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRender
*/
public class DependencySetup
{
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static void createSharedBindings()
{
@@ -66,7 +56,6 @@ public class DependencySetup
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
SingletonInjector.INSTANCE.bind(IDhApiCustomRenderObjectFactory.class, GenericRenderObjectFactory.INSTANCE);
}
public static void createServerBindings()
@@ -77,43 +66,8 @@ public class DependencySetup
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IMinecraftGLWrapper.class, MinecraftGLWrapper.INSTANCE);
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
}
public static void setRenderingApiBindings()
{
EDhApiRenderApi renderingApiEnum = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderingApiEnum == EDhApiRenderApi.AUTO)
{
#if MC_VER < MC_1_21_11
renderingApiEnum = EDhApiRenderApi.OPEN_GL;
#else
renderingApiEnum = EDhApiRenderApi.BLAZE_3D;
#endif
}
LOGGER.info("Setting DH Rendering API to: ["+renderingApiEnum+"].");
AbstractDhRenderApiDefinition renderDefinition;
if (renderingApiEnum == EDhApiRenderApi.OPEN_GL)
{
renderDefinition = new GlDhRenderApiDefinition();
}
else if (renderingApiEnum == EDhApiRenderApi.BLAZE_3D)
{
#if MC_VER <= MC_1_21_10
throw new IllegalStateException("["+renderingApiEnum+"] is not supported on this version of Minecraft.");
#else
renderDefinition = new BlazeDhRenderApiDefinition();
#endif
}
else
{
throw new IllegalStateException("No ["+ AbstractDhRenderApiDefinition.class.getSimpleName()+"] concrete implementation found for the value: ["+renderingApiEnum+"].");
}
renderDefinition.bindRenderers();
}
}
@@ -46,6 +46,7 @@ public class McObjectConverter
/** 4x4 float matrix converter */
@Deprecated
public static Mat4f Convert(
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
@@ -19,30 +19,22 @@
package com.seibel.distanthorizons.common.wrappers;
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
/**
* @author James Seibel
* @version 12-11-2021
*/
public class VersionConstants implements IVersionConstants
{
public static final VersionConstants INSTANCE = new VersionConstants();
private VersionConstants()
{
}
//=============//
// constructor //
//=============//
//region
private VersionConstants() { }
//endregion
//=========//
// methods //
//=========//
//region
@Override
public String getMinecraftVersion()
@@ -99,18 +91,4 @@ public class VersionConstants implements IVersionConstants
}
@Override
public EDhApiRenderApi getDefaultRenderingApi()
{
#if MC_VER <= MC_1_21_11
return EDhApiRenderApi.OPEN_GL;
#else
ERROR MC version constant missing
#endif
}
//endregion
}
@@ -30,33 +30,28 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.client.multiplayer.ClientLevel;
#if MC_VER > MC_1_17_1
import net.minecraft.core.Holder;
#endif
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import java.io.IOException;
import java.util.HashSet;
/**
* This handles creating abstract wrapper objects.
@@ -67,32 +62,9 @@ public class WrapperFactory implements IWrapperFactory
//=====================//
// internal properties //
//=====================//
//region
private AbstractDhRenderApiDefinition renderDefinition;
private AbstractDhRenderApiDefinition getRenderDefinition()
{
// delayed get to make sure we don't accidentally set the variable before it's bound
if (this.renderDefinition != null)
{
return this.renderDefinition;
}
this.renderDefinition = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
return this.renderDefinition;
}
//endregion
//==============//
// core methods //
//==============//
//region
@Override
public IBatchGeneratorEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
@@ -131,7 +103,7 @@ public class WrapperFactory implements IWrapperFactory
@Override
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
@Override
public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper)
public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper) // TODO is there a way we could get this without the levelWrapper? it isn't necessary but would clean up the code a bit
{
try
{
@@ -149,9 +121,9 @@ public class WrapperFactory implements IWrapperFactory
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
@Override
public ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
public HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
@Override
public ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
public HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
@Override
public void resetRendererIgnoredCaveBlocks() { BlockStateWrapper.clearRendererIgnoredCaveBlocks(); }
@@ -239,19 +211,10 @@ public class WrapperFactory implements IWrapperFactory
}
@Override public IVertexBufferWrapper createVboWrapper(String name) { return this.getRenderDefinition().createVboWrapper(name); }
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return this.getRenderDefinition().createLodContainerUniformWrapper(); }
@Override public IDhGenericObjectVertexBufferContainer createGenericObjectVboContainer() { return this.getRenderDefinition().createGenericVboContainer(); }
@Override public IDhGenericRenderer createGenericRenderer() { return this.getRenderDefinition().createGenericRenderer(); }
//endregion
//=============//
// api methods //
//=============//
//region
// documentation should be in the API interface
@@ -350,15 +313,12 @@ public class WrapperFactory implements IWrapperFactory
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
}
//endregion
//================//
// helper methods //
//================//
//region
private static String createWrapperErrorMessage(String wrapperName, String[] expectedClassNames, Object[] objectArray)
{
@@ -394,8 +354,4 @@ public class WrapperFactory implements IWrapperFactory
return message.toString();
}
//endregion
}
@@ -258,6 +258,7 @@ public class BiomeWrapper implements IBiomeWrapper
return this.serialString;
}
// TODO would it be worth while to cache these objects in a ConcurrentHashMap<string, IBiomeWrapper>?
public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException
{
// we need the final string for the concurrent hash map later
@@ -28,7 +28,6 @@ import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.BeaconBeamBlock;
import net.minecraft.world.level.block.Block;
@@ -44,7 +43,6 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
@@ -93,8 +91,17 @@ public class BlockStateWrapper implements IBlockStateWrapper
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
public static final String WATER_RESOURCE_LOCATION_STRING = "minecraft:water";
public static ObjectOpenHashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
public static ObjectOpenHashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
/** Used to handle older MC versions that don't have an simple way of getting the block's tags */
public static final List<String> OLD_BEACON_BASE_BLOCK_NAME_LIST = Arrays.asList(
"iron_block",
"gold_block",
"diamond_block",
"emerald_block",
"netherite_block"
);
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
/** keep track of broken blocks so we don't log every time */
#if MC_VER <= MC_1_21_10
@@ -129,7 +136,6 @@ public class BlockStateWrapper implements IBlockStateWrapper
//==============//
// constructors //
//==============//
//region
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper)
{
@@ -171,7 +177,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
}
private BlockStateWrapper(@Nullable BlockState blockState, ILevelWrapper levelWrapper)
private BlockStateWrapper(BlockState blockState, ILevelWrapper levelWrapper)
{
this.blockState = blockState;
this.serialString = this.serialize(levelWrapper);
@@ -185,21 +191,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
// beacon base blocks
#if MC_VER <= MC_1_18_2
// Used to handle older MC versions that don't have an simple way of getting the block's tags
List<String> oldBeaconBaseBlockNameList = Arrays.asList(
"iron_block",
"gold_block",
"diamond_block",
"emerald_block",
"netherite_block"
);
// Older MC versions are harder to get block tags, so just use a static list to determine beacon blocks
boolean isBeaconBaseBlock = false;
for (int i = 0; i < oldBeaconBaseBlockNameList.size(); i++)
for (int i = 0; i < OLD_BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
{
String baseBlockName = oldBeaconBaseBlockNameList.get(i);
String baseBlockName = OLD_BEACON_BASE_BLOCK_NAME_LIST.get(i);
if (lowercaseSerial.contains(baseBlockName))
{
isBeaconBaseBlock = true;
@@ -303,20 +299,17 @@ public class BlockStateWrapper implements IBlockStateWrapper
//LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.EDhApiBlockMaterialId+"]");
}
//endregion
//====================//
// LodBuilder methods //
//====================//
//region
/**
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
* This way the method won't accidentally be called before the deserialization can be completed.
*/
public static ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper)
public static HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper)
{
// use the cached version if possible
if (rendererIgnoredBlocks != null)
@@ -324,7 +317,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
return rendererIgnoredBlocks;
}
ObjectOpenHashSet<String> baseIgnoredBlock = new ObjectOpenHashSet<>();
HashSet<String> baseIgnoredBlock = new HashSet<>();
baseIgnoredBlock.add(AIR_STRING);
rendererIgnoredBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
return rendererIgnoredBlocks;
@@ -333,7 +326,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
* This way the method won't accidentally be called before the deserialization can be completed.
*/
public static ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper)
public static HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper)
{
// use the cached version if possible
if (rendererIgnoredCaveBlocks != null)
@@ -341,7 +334,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
return rendererIgnoredCaveBlocks;
}
ObjectOpenHashSet<String> baseIgnoredBlock = new ObjectOpenHashSet<>();
HashSet<String> baseIgnoredBlock = new HashSet<>();
baseIgnoredBlock.add(AIR_STRING);
rendererIgnoredCaveBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
return rendererIgnoredCaveBlocks;
@@ -350,19 +343,14 @@ public class BlockStateWrapper implements IBlockStateWrapper
public static void clearRendererIgnoredBlocks() { rendererIgnoredBlocks = null; }
public static void clearRendererIgnoredCaveBlocks() { rendererIgnoredCaveBlocks = null; }
//endregion
//=====================//
// lod builder helpers //
//=====================//
//region
private static ObjectOpenHashSet<IBlockStateWrapper> getAllBlockWrappers(ConfigEntry<String> config, ObjectOpenHashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
private static HashSet<IBlockStateWrapper> getAllBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
{
// get the base blocks
ObjectOpenHashSet<String> blockStringList = new ObjectOpenHashSet<>();
HashSet<String> blockStringList = new HashSet<>();
if (baseResourceLocations != null)
{
blockStringList.addAll(baseResourceLocations);
@@ -377,10 +365,10 @@ public class BlockStateWrapper implements IBlockStateWrapper
return getAllBlockWrappers(blockStringList, levelWrapper);
}
private static ObjectOpenHashSet<IBlockStateWrapper> getAllBlockWrappers(ObjectOpenHashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
private static HashSet<IBlockStateWrapper> getAllBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
{
// deserialize each of the given resource locations
ObjectOpenHashSet<IBlockStateWrapper> blockStateWrappers = new ObjectOpenHashSet<>();
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
for (String blockResourceLocation : blockResourceLocationSet)
{
try
@@ -429,14 +417,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
return blockStateWrappers;
}
//endregion
//=================//
// wrapper methods //
//=================//
//region
@Override
public int getOpacity() { return this.opacity; }
@@ -544,37 +529,25 @@ public class BlockStateWrapper implements IBlockStateWrapper
public boolean isAir() { return this.isAir(this.blockState); }
public boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
private Boolean blockIsSolid = null;
@Override
public boolean isSolid()
{
if (this.isAir()
|| this.blockState == null) // == null isn't necessary since its handled in isAir() but is here to prevent intellij from complaining
if (this.isAir())
{
return false;
}
// cached since getCollisionShape() is a dictionary lookup that allocates objects
// and this call is used in a high traffic location
if (this.blockIsSolid != null)
{
return this.blockIsSolid;
}
#if MC_VER < MC_1_20_1
this.blockIsSolid = this.blockState.getMaterial().isSolid();
return this.blockState.getMaterial().isSolid();
#else
this.blockIsSolid = !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
return !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
#endif
return this.blockIsSolid;
}
@Override
public boolean isLiquid()
{
if (this.isAir()
|| this.blockState == null) // == null isn't necessary since its handled in isAir() but is here to prevent intellij from complaining
if (this.isAir())
{
return false;
}
@@ -606,14 +579,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
@Override
public String toString() { return this.getSerialString(); }
//endregion
//=======================//
// serialization methods //
//=======================//
//region
private String serialize(ILevelWrapper levelWrapper)
{
@@ -841,14 +811,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
return stringBuilder.toString();
}
//endregion
//==============//
// Iris methods //
//==============//
//region
private EDhApiBlockMaterial calculateEDhApiBlockMaterialId()
{
@@ -898,10 +865,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
{
return EDhApiBlockMaterial.METAL;
}
else if (
serialString.contains("grass_block")
|| serialString.contains("grass_slab")
)
else if (serialString.contains("grass_block"))
{
return EDhApiBlockMaterial.GRASS;
}
@@ -956,7 +920,4 @@ public class BlockStateWrapper implements IBlockStateWrapper
}
}
//endregion
}
@@ -322,7 +322,7 @@ public class ClientBlockStateColorCache
return quads;
}
/** if multiple frames are present, just the first one will be used */
//TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, EColorMode colorMode)
{
int count = 0;
@@ -41,7 +41,6 @@ import net.minecraft.world.level.levelgen.Heightmap;
import com.seibel.distanthorizons.core.logging.DhLogger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
#if MC_VER >= MC_1_17_1
import net.minecraft.core.QuartPos;
@@ -82,8 +81,6 @@ public class ChunkWrapper implements IChunkWrapper
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
public static final Set<String> LOGGED_BLOCK_GET_ERRORS = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
private static boolean heightmapThreadWarningLogged = false;
@@ -253,7 +250,6 @@ public class ChunkWrapper implements IChunkWrapper
if (heightmapThreadWarningLogged
&& !DhApi.isDhThread())
{
heightmapThreadWarningLogged = true;
LOGGER.warn("ChunkWrapper Height maps created on non-DH thread ["+Thread.currentThread().getName()+"]. This may cause stuttering.");
}
@@ -375,19 +371,8 @@ public class ChunkWrapper implements IChunkWrapper
blockPos.setY(relY);
blockPos.setZ(relZ);
try
{
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
}
catch (Exception e)
{
if (LOGGED_BLOCK_GET_ERRORS.add(e.getMessage()))
{
LOGGER.warn("Failed to get block from chunk ["+this.chunkPos+"] at relative block pos ["+relX+","+relY+","+relZ+"], air will be used instead. This error message will only be logged once. error: ["+e.getMessage()+"].", e);
}
return BlockStateWrapper.AIR;
}
// TODO copy into pooled array, this isn't thread safe and can cause MC to throw errors if the chunk is loaded
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
}
@Override
@@ -399,20 +384,8 @@ public class ChunkWrapper implements IChunkWrapper
pos.setX(relX);
pos.setY(relY);
pos.setZ(relZ);
try
{
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(pos), this.wrappedLevel, guess);
}
catch (Exception e)
{
if (LOGGED_BLOCK_GET_ERRORS.add(e.getMessage()))
{
LOGGER.warn("Failed to get block from chunk ["+this.chunkPos+"] at relative block pos ["+relX+","+relY+","+relZ+"], air will be used instead. This error message will only be logged once. error: ["+e.getMessage()+"].", e);
}
return BlockStateWrapper.AIR;
}
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(pos), this.wrappedLevel, guess);
}
/**
@@ -440,10 +413,8 @@ public class ChunkWrapper implements IChunkWrapper
LevelChunkSection section = sections[i];
if (section != null)
{
// Implementation notes:
// implement section cloning for older MC versions, only 1.21.4 MC (and maybe other semi recent versions) have a clean way to handle this
// we probably want a wrapper object instead
// TODO implement section cloning for older MC versions, only 1.21.4 MC (and maybe other semi recent versions) have a clean way to handle this
// TODO we probably want a wrapper object instead
#if MC_VER < MC_1_21_4
this.levelChunkSections[i] = section;
#else
@@ -27,6 +27,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.AnnotationUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
@@ -123,9 +124,9 @@ public class ClassicConfigGUI
/** if you want to get this config gui's screen call this */
public static Screen getScreen(Screen parent, String category)
{ return new DhConfigScreen(parent, category); }
{ return new ConfigScreen(parent, category); }
private static class DhConfigScreen extends DhScreen
private static class ConfigScreen extends DhScreen
{
private static final ILangWrapper LANG_WRAPPER = SingletonInjector.INSTANCE.get(ILangWrapper.class);
@@ -145,7 +146,7 @@ public class ClassicConfigGUI
// constructor //
//=============//
protected DhConfigScreen(Screen parent, String category)
protected ConfigScreen(Screen parent, String category)
{
super(Translatable(
LANG_WRAPPER.langExists(ModInfo.ID + ".config" + (category.isEmpty() ? "." + category : "") + ".title") ?
@@ -302,10 +303,6 @@ public class ClassicConfigGUI
{
setupTextMenuOption(configEntry, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
}
else if (configValueClass == Float.class)
{
setupTextMenuOption(configEntry, Float::parseFloat, DECIMAL_ONLY_REGEX, false);
}
else if (configValueClass == String.class || configValueClass == List.class)
{
// For string or list
@@ -322,10 +319,6 @@ public class ClassicConfigGUI
Class<? extends Enum<?>> configEnumClass = (Class<? extends Enum<?>>) configValueClass;
setupEnumMenuOption(enumConfigEntry, configEnumClass);
}
else
{
LOGGER.error("No definition for config with type: ["+configValueClass.getName()+"], for config: ["+configMenuOption.name+"].");
}
}
}
@@ -581,7 +574,7 @@ public class ClassicConfigGUI
optionFieldPosX, optionFieldPosZ,
ConfigScreenConfigs.OPTION_FIELD_WIDTH - 4, ConfigScreenConfigs.CATEGORY_BUTTON_HEIGHT,
Translatable(""));
widget.setMaxLength(3_000_000); // hopefully 3 million characters should be enough for any normal use-case, lol
widget.setMaxLength(ConfigScreenConfigs.OPTION_FIELD_WIDTH);
widget.insertText(String.valueOf(configEntry.get()));
Predicate<String> processor = configGuiInfo.tooltipFunction.apply(widget, this.doneButton);
@@ -765,7 +758,7 @@ public class ClassicConfigGUI
}
DhButtonEntry button = DhButtonEntry.BUTTON_BY_WIDGET.get(hoveredWidget);
ButtonEntry button = ButtonEntry.BUTTON_BY_WIDGET.get(hoveredWidget);
// A quick fix for tooltips on linked entries
@@ -831,7 +824,7 @@ public class ClassicConfigGUI
// helper classes //
//================//
public static class ConfigListWidget extends ContainerObjectSelectionList<DhButtonEntry>
public static class ConfigListWidget extends ContainerObjectSelectionList<ButtonEntry>
{
Font textRenderer;
@@ -847,15 +840,15 @@ public class ClassicConfigGUI
this.textRenderer = minecraftClient.font;
}
public void addButton(DhConfigScreen gui, AbstractConfigBase dhConfigType, AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
{ this.addEntry(new DhButtonEntry(gui, dhConfigType, button, text, resetButton, indexButton)); }
public void addButton(ConfigScreen gui, AbstractConfigBase dhConfigType, AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
{ this.addEntry(new ButtonEntry(gui, dhConfigType, button, text, resetButton, indexButton)); }
@Override
public int getRowWidth() { return 10_000; }
public AbstractWidget getHoveredButton(double mouseX, double mouseY)
{
for (DhButtonEntry buttonEntry : this.children())
for (ButtonEntry buttonEntry : this.children())
{
AbstractWidget button = buttonEntry.button;
if (button != null
@@ -886,13 +879,13 @@ public class ClassicConfigGUI
}
public static class DhButtonEntry extends ContainerObjectSelectionList.Entry<DhButtonEntry>
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry>
{
private static final Font textRenderer = Minecraft.getInstance().font;
private final AbstractWidget button;
private final DhConfigScreen gui;
private final ConfigScreen gui;
private final AbstractConfigBase dhConfigType;
private final AbstractWidget resetButton;
@@ -904,12 +897,12 @@ public class ClassicConfigGUI
private final EConfigCommentTextPosition textPosition;
public static final Map<AbstractWidget, Component> TEXT_BY_WIDGET = new HashMap<>();
public static final Map<AbstractWidget, DhButtonEntry> BUTTON_BY_WIDGET = new HashMap<>();
/// TODO we should just use a wrapper or something
public static final Map<AbstractWidget, ButtonEntry> BUTTON_BY_WIDGET = new HashMap<>();
public DhButtonEntry(
DhConfigScreen gui, AbstractConfigBase dhConfigType,
public ButtonEntry(ConfigScreen gui, AbstractConfigBase dhConfigType,
AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
{
TEXT_BY_WIDGET.put(button, text);
@@ -963,17 +956,11 @@ public class ClassicConfigGUI
{
try
{
// setting the "y" variable is necessary so each child item
// renders at the correct height,
// if not set they will render off-screen.
#if MC_VER < MC_1_21_9
// Y value passed in from method args
#else
int y = this.getY();
int y = this.getY(); /// TODO why is the Y value being set during render?
#endif
if (this.button != null)
{
SetY(this.button, y);
@@ -3,6 +3,7 @@ package com.seibel.distanthorizons.common.wrappers.gui;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.gui.JavaScreenHandlerScreen;
import net.minecraft.client.gui.screens.Screen;
import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -10,13 +11,21 @@ public class GetConfigScreen
{
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static EType useScreen = EType.Classic;
public enum EType
{
Classic,
JavaSwing;
}
public static Screen getScreen(Screen parent)
{
// TODO it'd be nice to have this run automatically on startup
// but this will only work once MC has added our lang file,
// which won't be for sure added until we request a GUI
if (ModInfo.IS_DEV_BUILD)
{
// it'd be nice to have this run automatically on startup
// but this will only work once MC has added our lang file,
// which won't be for sure added until we request a GUI
String missingLangEntries = ConfigHandler.INSTANCE.generateLang(true, true);
// trim to remove any newlines/spaces
@@ -30,7 +39,17 @@ public class GetConfigScreen
}
}
return ClassicConfigGUI.getScreen(parent, "client");
switch (useScreen)
{
case Classic:
return ClassicConfigGUI.getScreen(parent, "client");
case JavaSwing:
//return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
default:
throw new IllegalArgumentException("No config screen implementation defined for ["+useScreen+"].");
}
}
}
@@ -106,7 +106,8 @@ public class TexturedButtonWidget extends Button
#if MC_VER < MC_1_20_2
super(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text);
#else
// We don't pass in the text option since it will render (we normally pass it in for narration)
// We don't pass on the text option as otherwise it will render (we normally pass it for narration)
// TODO: Find a fix for it
super(x, y, width, height, Component.empty(), pressAction, DEFAULT_NARRATION);
this.u = u;
@@ -37,6 +37,8 @@ import java.util.*;
*
* @author coolGi
*/
// TODO: After finishing the config, rewrite this in openGL as well
// TODO: Make this
public class ChangelogScreen extends DhScreen
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -34,6 +34,8 @@ import java.util.*;
*
* @author coolGi
*/
// TODO: After finishing the config, rewrite this in Java Swing as well
// and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192
public class UpdateModScreen extends DhScreen
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -103,7 +105,7 @@ public class UpdateModScreen extends DhScreen
195, 65,
// Create the button and tell it where to go
// For now it goes to the client option by default
(buttonWidget) -> LOGGER.info("Nice, you found an Easter egg :)"),
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
// Add a title to the button
Translatable(ModInfo.ID + ".updater.title"),
// Dont render the background of the button
@@ -184,7 +186,9 @@ public class UpdateModScreen extends DhScreen
// background blur is already being rendered, rendering again causes the game to crash
#endif
// TODO: add the tooltips for the buttons
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
// TODO: Add tooltips
// Render the text's
this.DhDrawCenteredString(matrices, this.font,
@@ -24,7 +24,7 @@ import java.io.File;
import com.mojang.blaze3d.platform.Window;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -56,11 +56,6 @@ import net.minecraft.network.chat.TextComponent;
import net.minecraft.util.profiling.Profiler;
#endif
#if MC_VER <= MC_1_21_10
import net.minecraft.client.GraphicsStatus;
#else
#endif
/**
* A singleton that wraps the Minecraft object.
*
@@ -81,7 +76,6 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
//======================//
// multiplayer handling //
//======================//
//region
@Override
public boolean hasSinglePlayerServer() { return MINECRAFT.hasSingleplayerServer(); }
@@ -131,14 +125,11 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return (server != null) ? server.version.getString() : "UNKOWN";
}
//endregion
//=================//
// player handling //
//=================//
//region
public LocalPlayer getPlayer() { return MINECRAFT.player; }
@@ -175,14 +166,11 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return new DhChunkPos(playerPos.x, playerPos.z);
}
//endregion
//================//
// level handling //
//================//
//region
@Nullable
@Override
@@ -201,14 +189,11 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return ClientLevelWrapper.getWrapper(level, bypassLevelKeyManager);
}
//endregion
//===========//
// messaging //
//===========//
//region
@Override
public void sendChatMessage(String string)
@@ -225,7 +210,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
#else
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread(() ->
GLProxy.queueRunningOnRenderThread(() ->
{
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
});
@@ -248,19 +233,14 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
#endif
}
//endregion
//==========================//
// vanilla option overrides //
//==========================//
//region
public void disableVanillaClouds()
{
LOGGER.info("Disabling vanilla clouds... This is done to prevent vanilla clouds from rendering on top of Distant Horizons LODs.");
#if MC_VER <= MC_1_18_2
MINECRAFT.options.renderClouds = CloudStatus.OFF;
#else
@@ -270,8 +250,6 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
public void disableVanillaChunkFadeIn()
{
LOGGER.info("Disabling vanilla chunk fade in... This is done to prevent vanilla chunks from flashing on the Distant Horizons boarder when moving (which is distracting).");
#if MC_VER <= MC_1_21_10
// chunk fade in was added MC 1.21.11
#else
@@ -279,41 +257,11 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
#endif
}
public void disableFabulousTransparency()
{
String reasoning = "This is done to fix vanilla chunks (specifically water blocks) not fading into Distant Horizons LODs when DH's 'Vanilla Fade' option is enabled.";
#if MC_VER <= MC_1_18_2
LOGGER.info("Disabling fabulous graphics... "+reasoning);
GraphicsStatus oldGraphicsStatus = MINECRAFT.options.graphicsMode;
if (oldGraphicsStatus == GraphicsStatus.FABULOUS)
{
MINECRAFT.options.graphicsMode = GraphicsStatus.FANCY;
}
#elif MC_VER <= MC_1_21_10
LOGGER.info("Disabling fabulous graphics... "+reasoning);
GraphicsStatus oldGraphicsStatus = MINECRAFT.options.graphicsMode().get();
if (oldGraphicsStatus == GraphicsStatus.FABULOUS)
{
MINECRAFT.options.graphicsMode().set(GraphicsStatus.FANCY);
}
#else
LOGGER.info("Disabling improved transparency... "+reasoning);
MINECRAFT.options.improvedTransparency().set(false);
#endif
}
//endregion
//======//
// misc //
//======//
//region
/**
* no override and not included in {@link IMinecraftClientWrapper}
@@ -367,29 +315,20 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
#endif
}
@Override
public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); }
//endregion
//=============//
// mod support //
//=============//
//region
@Override
public Object getOptionsObject() { return MINECRAFT.options; }
//endregion
//========//
// shared //
//========//
//region
@Override
public boolean isDedicatedServer() { return false; }
@@ -411,8 +350,6 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
}
}
//endregion
}
@@ -25,8 +25,8 @@ import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.opengl.GlStateManager;
#endif
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.opengl.GL32;
@@ -50,7 +50,7 @@ import org.lwjgl.opengl.GL32;
* This may slow down some low end GPUs that are driver limited,
* however James would rather have slow correct rendering vs fast broken rendering.
*/
public class MinecraftGLWrapper
public class MinecraftGLWrapper implements IMinecraftGLWrapper
{
public static final MinecraftGLWrapper INSTANCE = new MinecraftGLWrapper();
@@ -66,12 +66,14 @@ public class MinecraftGLWrapper
// scissor //
/** @see GL32#GL_SCISSOR_TEST */
@Override
public void enableScissorTest()
{
GL32.glEnable(GL32.GL_SCISSOR_TEST);
GlStateManager._enableScissorTest();
}
/** @see GL32#GL_SCISSOR_TEST */
@Override
public void disableScissorTest()
{
GL32.glDisable(GL32.GL_SCISSOR_TEST);
@@ -90,12 +92,14 @@ public class MinecraftGLWrapper
// depth //
/** @see GL32#GL_DEPTH_TEST */
@Override
public void enableDepthTest()
{
GL32.glEnable(GL32.GL_DEPTH_TEST);
GlStateManager._enableDepthTest();
}
/** @see GL32#GL_DEPTH_TEST */
@Override
public void disableDepthTest()
{
GL32.glDisable(GL32.GL_DEPTH_TEST);
@@ -103,6 +107,7 @@ public class MinecraftGLWrapper
}
/** @see GL32#glDepthFunc(int) */
@Override
public void glDepthFunc(int func)
{
GL32.glDepthFunc(func);
@@ -110,12 +115,14 @@ public class MinecraftGLWrapper
}
/** @see GL32#glDepthMask(boolean) */
@Override
public void enableDepthMask()
{
GL32.glDepthMask(true);
GlStateManager._depthMask(true);
}
/** @see GL32#glDepthMask(boolean) */
@Override
public void disableDepthMask()
{
GL32.glDepthMask(false);
@@ -126,12 +133,14 @@ public class MinecraftGLWrapper
// blending //
/** @see GL32#GL_BLEND */
@Override
public void enableBlend()
{
GL32.glEnable(GL32.GL_BLEND);
GlStateManager._enableBlend();
}
/** @see GL32#GL_BLEND */
@Override
public void disableBlend()
{
GL32.glDisable(GL32.GL_BLEND);
@@ -139,6 +148,7 @@ public class MinecraftGLWrapper
}
/** @see GL32#glBlendFunc */
@Override
public void glBlendFunc(int sfactor, int dfactor)
{
GL32.glBlendFunc(sfactor, dfactor);
@@ -148,6 +158,7 @@ public class MinecraftGLWrapper
#endif
}
/** @see GL32#glBlendFuncSeparate */
@Override
public void glBlendFuncSeparate(int sfactorRGB, int dfactorRGB, int sfactorAlpha, int dfactorAlpha)
{
GL32.glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
@@ -158,6 +169,7 @@ public class MinecraftGLWrapper
// frame buffers //
/** @see GL32#glBindFramebuffer */
@Override
public void glBindFramebuffer(int target, int framebuffer)
{
GL32.glBindFramebuffer(target, framebuffer);
@@ -168,29 +180,16 @@ public class MinecraftGLWrapper
// buffers //
/** @see GL32#glGenBuffers() */
@Override
public int glGenBuffers()
{ return GL32.glGenBuffers(); }
{ return GlStateManager._glGenBuffers(); }
/** @see GL32#glDeleteBuffers(int) */
/** @see GL32#glDeleteBuffers(int) */
@Override
public void glDeleteBuffers(int buffer)
{
GL32.glDeleteBuffers(buffer);
// attempt to fix a bug with Mac where de-allocated buffers
// are still being used, causing a SIGSEGV native crash
// and/or corrupting native memory
if (EPlatform.get() == EPlatform.MACOS)
{
// force the delete buffer (and any other in-flight) GL
// commands to finish before continuing
GL32.glFinish();
// James hates this idea.
// He kinda hopes it doesn't help,
// but maybe metal's API just doesn't finish correctly so we need to wait a moment longer before continuing.
try { Thread.sleep(1); } catch (InterruptedException ignore) { }
}
// MC's implementation has a bug where it will throw:
// GL_INVALID_OPERATION in glBufferData(immutable)
// when attempting to delete Storage Buffers
@@ -202,12 +201,14 @@ public class MinecraftGLWrapper
// culling //
/** @see GL32#GL_CULL_FACE */
@Override
public void enableFaceCulling()
{
GL32.glEnable(GL32.GL_CULL_FACE);
GlStateManager._enableCull();
}
/** @see GL32#GL_CULL_FACE */
@Override
public void disableFaceCulling()
{
GL32.glDisable(GL32.GL_CULL_FACE);
@@ -218,22 +219,27 @@ public class MinecraftGLWrapper
// textures //
/** @see GL32#glGenTextures() */
@Override
public int glGenTextures() { return GlStateManager._genTexture(); }
/** @see GL32#glDeleteTextures(int) */
@Override
public void glDeleteTextures(int texture) { GlStateManager._deleteTexture(texture); }
/** @see GL32#glActiveTexture(int) */
@Override
public void glActiveTexture(int textureId)
{
GL32.glActiveTexture(textureId);
GlStateManager._activeTexture(textureId);
}
@Override
public int getActiveTexture() { return GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D); }
/**
* Always binds to {@link GL32#GL_TEXTURE_2D}
* @see GL32#glBindTexture(int, int)
*/
@Override
public void glBindTexture(int texture)
{
GL32.glBindTexture(GL32.GL_TEXTURE_2D, texture);
@@ -242,4 +248,5 @@ public class MinecraftGLWrapper
}
@@ -29,6 +29,7 @@ import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -85,7 +86,6 @@ import com.mojang.blaze3d.opengl.GlTexture;
#if MC_VER <= MC_1_21_10
#else
import net.minecraft.world.attribute.EnvironmentAttributes;
import com.mojang.blaze3d.textures.GpuTexture;
#endif
/**
@@ -175,18 +175,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
}
@Override
public float getPartialTickTime()
{
#if MC_VER < MC_1_21_1
return MC.getFrameTime();
#elif MC_VER < MC_1_21_3
return MC.getTimer().getRealtimeDeltaTicks();
#else
return MC.deltaTracker.getRealtimeDeltaTicks();
#endif
}
@Override
public Color getFogColor(float partialTicks)
{
@@ -273,16 +261,24 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{
if (MC.level.dimensionType().hasSkyLight())
{
float frameTime;
#if MC_VER < MC_1_21_1
frameTime = MC.getFrameTime();
#elif MC_VER < MC_1_21_3
frameTime = MC.getTimer().getRealtimeDeltaTicks();
#elif MC_VER <= MC_1_21_10
frameTime = MC.deltaTracker.getGameTimeDeltaTicks();
#else
frameTime = 0f; // unused
#endif
#if MC_VER < MC_1_17_1
float frameTime = this.getPartialTickTime();
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), frameTime);
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
#elif MC_VER < MC_1_21_3
float frameTime = this.getPartialTickTime();
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
#elif MC_VER <= MC_1_21_10
float frameTime = this.getPartialTickTime();
int argbColorInt = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
return ColorUtil.toColorObjARGB(argbColorInt);
#else
@@ -303,23 +299,14 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public int getRenderDistance()
{
#if MC_VER <= MC_1_17_1
#if MC_VER < MC_1_18_2
//FIXME: How to resolve this?
return MC.options.renderDistance;
#else
return MC.options.getEffectiveRenderDistance();
#endif
}
@Override
public int getFrameLimit()
{
#if MC_VER <= MC_1_18_2
return MC.options.framerateLimit;
#else
return MC.options.framerateLimit().get();
#endif
}
protected RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); }
@Override
@@ -488,20 +475,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
wrapper.setLightmapId(tetxureId);
}
#if MC_VER <= MC_1_21_10
#else
public void setLightmapGpuTexture(GpuTexture gpuTexture, IClientLevelWrapper level)
{
// Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same
// object for the same MC level and/or the same hash,
// so this will have to do for now
IDimensionTypeWrapper dimensionType = level.getDimensionType();
LightMapWrapper wrapper = this.lightmapByDimensionType.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
wrapper.setLightmapGpuTexture(gpuTexture);
}
#endif
@Override
public float getShade(EDhDirection lodDirection)
{
@@ -20,64 +20,39 @@
package com.seibel.distanthorizons.common.wrappers.misc;
import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.opengl.GL32;
#if MC_VER < MC_1_21_3
import java.nio.ByteBuffer;
#else
#endif
#if MC_VER <= MC_1_21_10
#else
import com.mojang.blaze3d.textures.GpuTexture;
#endif
public class LightMapWrapper implements ILightMapWrapper
{
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
/**
* which texture index IE 0,1,2... the lightmap will be bound to. <Br>
* Related to but different from {@link GL32#GL_TEXTURE0}.
*/
public static final int GL_BOUND_INDEX = 0;
private int textureId = 0;
#if MC_VER <= MC_1_21_10
#else
private GpuTexture gpuTexture = null;
#endif
private final BlazeTextureViewWrapper lightmapTextureWrapper = new BlazeTextureViewWrapper();
//==============//
// constructors //
//==============//
//region
public LightMapWrapper() { }
//endregion
//==================//
// lightmap syncing //
//==================//
//region
public void uploadLightmap(NativeImage image)
{
#if MC_VER < MC_1_21_3
#if MC_VER < MC_1_21_5
int currentTexture = GLMC.getActiveTexture();
if (this.textureId == 0)
{
@@ -96,52 +71,42 @@ public class LightMapWrapper implements ILightMapWrapper
GLMC.glBindTexture(currentTexture);
}
#else
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.3");
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.5"); // TODO that MC version number is wrong, when did we actually start using setLightmapId()?
#endif
}
private void createLightmap(NativeImage image)
{
#if MC_VER < MC_1_21_3
#if MC_VER < MC_1_21_5
this.textureId = GLMC.glGenTextures();
GLMC.glBindTexture(this.textureId);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, image.format().glFormat(), image.getWidth(), image.getHeight(),
0, image.format().glFormat(), GL32.GL_UNSIGNED_BYTE, (ByteBuffer) null);
#else
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.3");
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.5"); // TODO that MC version number is wrong, when did we actually start using setLightmapId()?
#endif
}
public void setLightmapId(int minecraftLightmapTextureId)
public void setLightmapId(int minecraftLightmapTetxureId)
{
// just use the MC texture ID
this.textureId = minecraftLightmapTextureId;
this.textureId = minecraftLightmapTetxureId;
}
#if MC_VER <= MC_1_21_10
#else
public void setLightmapGpuTexture(GpuTexture gpuTexture)
{
this.gpuTexture = gpuTexture;
this.lightmapTextureWrapper.tryWrap(this.gpuTexture);
}
#endif
//endregion
//==============//
// lightmap use //
//==============//
//region
public BlazeTextureViewWrapper getTextureViewWrapper() { return this.lightmapTextureWrapper; }
public int getOpenGlId() { return this.textureId; }
//endregion
@Override
public void bind()
{
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
GLMC.glBindTexture(this.textureId);
}
@Override
public void unbind() { GLMC.glBindTexture(0); }
}
@@ -87,25 +87,21 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//=============//
// constructor //
//=============//
//region
protected ClientLevelWrapper(ClientLevel level) { this.level = level; }
//endregion
//==================//
// instance methods //
//==================//
//region
/**
* can be used when speed is important and the same level is likely to be passed in,
* IE rendering.
*/
@Nullable
public static IClientLevelWrapper getWrapperIfDifferent(@Nullable IClientLevelWrapper levelWrapper, @NotNull ClientLevel level)
public static IClientLevelWrapper getWrapperIfDifferent(@Nullable IClientLevelWrapper levelWrapper, @NotNull ClientLevel level) // TODO handle null level
{
if (KEYED_CLIENT_LEVEL_MANAGER.isEnabled() && KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel() != levelWrapper)
{
@@ -205,14 +201,11 @@ public class ClientLevelWrapper implements IClientLevelWrapper
}
}
//endregion
//====================//
// base level methods //
//====================//
//region
@Override
public int getBlockColor(DhBlockPos blockPos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockWrapper)
@@ -228,6 +221,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return blockColorCache.getColor((BiomeWrapper) biome, fullDataSource, blockPos);
}
@Override
public int getDirtBlockColor()
{
@@ -251,43 +245,24 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Override
public void clearBlockColorCache() { this.blockColorCacheByBlockState.clear(); }
private IDimensionTypeWrapper dimensionTypeWrapper = null;
@Override
public IDimensionTypeWrapper getDimensionType()
{
// cached since dimensionType() is a dictionary lookup that allocates objects
// and this call is used in a high traffic location
if (this.dimensionTypeWrapper != null)
{
return this.dimensionTypeWrapper;
}
#if MC_VER <= MC_1_21_10
this.dimensionTypeWrapper = DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType());
return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType());
#else
this.dimensionTypeWrapper = DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType(), this.getDimensionName());
return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType(), this.getDimensionName());
#endif
return this.dimensionTypeWrapper;
}
private String dimensionName = null;
@Override
public String getDimensionName()
{
// cached since toString() allocates a new string each time
// and this call is used in a high traffic location
if (this.dimensionName != null)
{
return this.dimensionName;
}
#if MC_VER <= MC_1_21_10
this.dimensionName = this.level.dimension().location().toString();
return this.level.dimension().location().toString();
#else
this.dimensionName = this.level.dimension().identifier().toString();
return this.level.dimension().identifier().toString();
#endif
return this.dimensionName;
}
@Override
@@ -301,72 +276,25 @@ public class ClientLevelWrapper implements IClientLevelWrapper
public ClientLevel getLevel() { return this.level; }
private Boolean dimHasCeiling = null;
@Override
public boolean hasCeiling()
{
// cached since dimensionType() is a dictionary lookup that allocates objects
// and this call is used in a high traffic location
if (this.dimHasCeiling != null)
{
return this.dimHasCeiling;
}
this.dimHasCeiling = this.level.dimensionType().hasCeiling();
return this.dimHasCeiling;
}
public boolean hasCeiling() { return this.level.dimensionType().hasCeiling(); }
private Boolean dimHasSkyLight = null;
@Override
public boolean hasSkyLight()
{
// cached since dimensionType() is a dictionary lookup that allocates objects
// and this call is used in a high traffic location
if (this.dimHasSkyLight != null)
{
return this.dimHasSkyLight;
}
this.dimHasSkyLight = this.level.dimensionType().hasSkyLight();
return this.dimHasSkyLight;
}
public boolean hasSkyLight() { return this.level.dimensionType().hasSkyLight(); }
private Integer dimMaxHeight = null;
@Override
public int getMaxHeight()
{
// cached since getHeight() is a dictionary lookup that allocates objects
// and this call is used in a high traffic location
if (this.dimMaxHeight != null)
{
return this.dimMaxHeight;
}
this.dimMaxHeight = this.level.getHeight();
return this.dimMaxHeight;
}
public int getMaxHeight() { return this.level.getHeight(); }
private Integer dimMinHeight = null;
@Override
public int getMinHeight()
{
// cached since getMinY() is a dictionary lookup that allocates objects
// and this call is used in a high traffic location
if (this.dimMinHeight != null)
{
return this.dimMinHeight;
}
#if MC_VER < MC_1_17_1
this.dimMinHeight = 0;
return 0;
#elif MC_VER < MC_1_21_3
this.dimMinHeight = this.level.getMinBuildHeight();
return this.level.getMinBuildHeight();
#else
this.dimMinHeight = this.level.getMinY();
return this.level.getMinY();
#endif
return this.dimMinHeight;
}
@Override
@@ -390,14 +318,12 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return this.dhLevel.getSaveStructure().getSaveFolder(this);
}
//endregion
//===================//
// generic rendering //
//===================//
//region
@Override
public void setDhLevel(IDhLevel dhLevel) { this.dhLevel = dhLevel; }
@@ -484,14 +410,11 @@ public class ClientLevelWrapper implements IClientLevelWrapper
#endif
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public String toString()
@@ -504,8 +427,4 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}";
}
//endregion
}
@@ -29,8 +29,6 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandl
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.api.internal.chunkUpdating.ChunkUpdateQueueManager;
import com.seibel.distanthorizons.core.api.internal.chunkUpdating.WorldChunkUpdateManager;
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.config.Config;
@@ -592,11 +590,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
// usually ignoring the chunk's position is unnecessary,
// but this improves performance if a chunk update event does sneak through
ChunkUpdateQueueManager updateManager = WorldChunkUpdateManager.INSTANCE.getByLevelWrapper(this.dhServerLevel.getServerLevelWrapper());
if (updateManager != null)
{
updateManager.addPosToIgnore(chunkWrapper.getChunkPos());
}
SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(chunkWrapper.getChunkPos());
});
@@ -722,19 +716,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
this.chunkSaveIgnoreTimer.schedule(new TimerTask()
{
@Override
public void run()
{
ChunkUpdateQueueManager updateManager = WorldChunkUpdateManager.INSTANCE.getByLevelWrapper(BatchGenerationEnvironment.this.dhServerLevel.getServerLevelWrapper());
if (updateManager != null)
{
updateManager.addPosToIgnore(chunkWrapper.getChunkPos());
}
else
{
// shouldn't happen, but just in case
LOGGER.warn("Unable to find chunk update manager for server level ["+BatchGenerationEnvironment.this.dhServerLevel+"], chunk updates may fail.");
}
}
public void run() { SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.removePosToIgnore(chunkWrapper.getChunkPos()); }
}, MS_TO_IGNORE_CHUNK_AFTER_COMPLETION);
}
}
@@ -5,13 +5,10 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.api.internal.chunkUpdating.ChunkUpdateQueueManager;
import com.seibel.distanthorizons.core.api.internal.chunkUpdating.WorldChunkUpdateManager;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.DhServerLevel;
import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -193,7 +190,7 @@ public class InternalServerGenerator
while (chunkPosIterator.hasNext())
{
ChunkPos chunkPos = chunkPosIterator.next();
this.releaseChunkFromServer(this.params.mcServerLevel, this.params.dhServerLevel, chunkPos);
this.releaseChunkFromServer(this.params.mcServerLevel, chunkPos);
}
}
}
@@ -237,11 +234,7 @@ public class InternalServerGenerator
ServerLevel level = this.params.mcServerLevel;
// ignore chunk update events for this position
ChunkUpdateQueueManager updateManager = WorldChunkUpdateManager.INSTANCE.getByLevelWrapper(this.params.dhServerLevel.getServerLevelWrapper());
if (updateManager != null)
{
updateManager.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z));
}
SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z));
#if MC_VER < MC_1_21_5
int chunkLevel = 33; // 33 is equivalent to FULL Chunk
@@ -277,7 +270,7 @@ public class InternalServerGenerator
* mitigates out of memory issues in the vanilla chunk system. <br>
* See: https://github.com/pop4959/Chunky/pull/383
*/
private void releaseChunkFromServer(ServerLevel level, IDhServerLevel dhLevel, ChunkPos chunkPos)
private void releaseChunkFromServer(ServerLevel level, ChunkPos chunkPos)
{
level.getChunkSource().chunkMap.mainThreadExecutor.execute(() ->
{
@@ -302,19 +295,7 @@ public class InternalServerGenerator
this.chunkSaveIgnoreTimer.schedule(new TimerTask()
{
@Override
public void run()
{
ChunkUpdateQueueManager updateManager = WorldChunkUpdateManager.INSTANCE.getByLevelWrapper(dhLevel.getServerLevelWrapper());
if (updateManager != null)
{
updateManager.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z));
}
else
{
// shouldn't happen, but just in case
LOGGER.warn("Unable to find chunk update manager for server level ["+dhLevel+"], chunk updates may fail.");
}
}
public void run() { SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.removePosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z)); }
}, MS_TO_IGNORE_CHUNK_AFTER_COMPLETION);
}
@@ -216,6 +216,13 @@ public class DhLitWorldGenRegion extends WorldGenRegion
public LevelTickAccess<Fluid> getFluidTicks() { return BlackholeTickAccess.emptyLevelList(); }
#endif
// TODO Check this
// @Override
// public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
// StructureFeature<?> structureFeature) {
// return structFeat.startsForFeature(sectionPos, structureFeature);
// }
// Skip updating the related tile entities
@Override
public boolean setBlock(BlockPos blockPos, BlockState blockState, int i, int j)
@@ -388,10 +395,8 @@ public class DhLitWorldGenRegion extends WorldGenRegion
if (chunkStatus != ChunkStatus.EMPTY
&& chunkStatus != debugTriggeredForStatus)
{
// logger disabled since this doesn't seem to significantly harm anything
// and it causes more confusion to end users when they see it in the log
//LOGGER.info("WorldGen requiring [" + chunkStatus + "]"
// + " is outside the expected range. Returning EMPTY chunk.");
LOGGER.info("WorldGen requiring [" + chunkStatus + "]"
+ " is outside the expected range. Returning EMPTY chunk.");
debugTriggeredForStatus = chunkStatus;
}
@@ -67,8 +67,8 @@ public final class StepBiomes extends AbstractWorldGenStep
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers)
{
ArrayList<ChunkWrapper> chunksToGen = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToGen)
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToDo)
{
ChunkAccess chunk = chunkWrapper.getChunk();
@@ -37,10 +37,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public final class StepFeatures extends AbstractWorldGenStep
@@ -51,8 +48,6 @@ public final class StepFeatures extends AbstractWorldGenStep
private final BatchGenerationEnvironment environment;
public static final Set<String> LOGGED_ERRORS = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
//=============//
@@ -75,8 +70,8 @@ public final class StepFeatures extends AbstractWorldGenStep
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers)
{
ArrayList<ChunkWrapper> chunksToGen = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToGen)
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToDo)
{
ChunkAccess chunk = chunkWrapper.getChunk();
@@ -99,21 +94,15 @@ public final class StepFeatures extends AbstractWorldGenStep
Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter());
}
catch (ConcurrentModificationException e)
catch (ConcurrentModificationException e) // ReportedException
{
String message = "Concurrency issue when generating features for chunk at pos ["+chunkWrapper.getChunkPos()+"], error: ["+e.getMessage()+"], this message will only be logged once. This issue cannot be resolved from DH's end.";
if (LOGGED_ERRORS.add(message))
{
LOGGER.warn(message, e);
}
// TODO
}
catch (Exception e)
{
String message = "Unexpected issue when generating features for chunk at pos ["+chunkWrapper.getChunkPos()+"], error: ["+e.getMessage()+"].";
if (LOGGED_ERRORS.add(message))
{
LOGGER.warn(message, e);
}
LOGGER.warn("Unexpected issue when generating features for chunk at pos ["+chunkWrapper.getChunkPos()+"], error: ["+e.getMessage()+"].", e);
// FIXME: Features concurrent modification issue. Something about cocobeans might just
// error out. For now just retry.
}
}
}
@@ -67,8 +67,8 @@ public final class StepNoise extends AbstractWorldGenStep
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers)
{
ArrayList<ChunkWrapper> chunksToGen = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToGen)
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToDo)
{
ChunkAccess chunk = chunkWrapper.getChunk();
@@ -64,8 +64,8 @@ public final class StepStructureReference extends AbstractWorldGenStep
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers)
{
ArrayList<ChunkWrapper> chunksToGen = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToGen)
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunksToDo)
{
ChunkAccess chunk = chunkWrapper.getChunk();
this.environment.globalParams.generator.createReferences(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk);

Some files were not shown because too many files have changed in this diff Show More