Skip to content

Commit

Permalink
Working on blend state logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Aeltumn committed Nov 12, 2024
1 parent 5af67cb commit ab81b34
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.noxcrew.noxesium.feature.ui.render;

import com.noxcrew.noxesium.NoxesiumMod;
import com.noxcrew.noxesium.feature.ui.render.api.BlendState;
import com.noxcrew.noxesium.feature.ui.render.api.BlendStateHook;
import net.minecraft.client.gui.GuiGraphics;
import org.lwjgl.opengl.GL11;

import java.io.Closeable;
import java.nio.ByteBuffer;
Expand All @@ -10,7 +13,7 @@
/**
* Manages a buffer and its current dynamic fps.
*/
public class DynamicElement implements Closeable {
public class DynamicElement implements Closeable, BlendStateHook {

// Stores whether any elements were drawn.
public static boolean elementsWereDrawn = false;
Expand All @@ -22,6 +25,7 @@ public class DynamicElement implements Closeable {
private long nextCheck;
private long nextRender = -1;
private int failedCheckCount = 0;
private BlendState blendState;

/**
* The current fps at which we check for optimization steps.
Expand Down Expand Up @@ -142,7 +146,10 @@ public void tick() {
/**
* Updates the current state of this element.
*/
public boolean update(long nanoTime, GuiGraphics guiGraphics, Runnable draw) {
public boolean update(long nanoTime, GuiGraphics guiGraphics, BlendState blendState, Runnable draw) {
// Use the blend state while making edits for this object
this.blendState = blendState;

// Always start by awaiting the GPU fence
buffer.awaitFence();

Expand All @@ -164,9 +171,11 @@ public boolean update(long nanoTime, GuiGraphics guiGraphics, Runnable draw) {
// Bind the buffer, abort is something goes wrong
if (!buffer.bind(guiGraphics)) return false;

// Draw the layers onto the buffer
// Draw the layers onto the buffer while capturing the blending state
elementsWereDrawn = false;
SharedVertexBuffer.blendStateHook = this;
draw.run();
SharedVertexBuffer.blendStateHook = null;

// Actually render things to this buffer
guiGraphics.flush();
Expand All @@ -181,6 +190,71 @@ public boolean update(long nanoTime, GuiGraphics guiGraphics, Runnable draw) {
return true;
}

/*
Default blending is:
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(
GlStateManager.SourceFactor.SRC_ALPHA,
GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA,
GlStateManager.SourceFactor.ONE,
GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA
);
In vanilla we expect the following blend state changes:
Vignette has VIGNETTE_TRANSPARENCY with:
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR);
Crosshair has CROSSHAIR_TRANSPARENCY with:
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(
GlStateManager.SourceFactor.ONE_MINUS_DST_COLOR,
GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR,
GlStateManager.SourceFactor.ONE,
GlStateManager.DestFactor.ZERO
);
Nausea overlay has NAUSEA_OVERLAY_TRANSPARENCY with:
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(
GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE
);
Hotbar items use entity cutout which has NO_TRANSPARENCY with:
RenderSystem.disableBlend();
(default blend func is implied but unnecessary)
Hotbar item glints uses GLINT_TRANSPERNCY with:
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(
GlStateManager.SourceFactor.SRC_COLOR, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE
);
Likely other overlays used.
Our default blend function for drawing the buffers is:
GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA
*/

@Override
public boolean changeState(boolean newValue) {
if (newValue == blendState.enabled()) return true;
// System.out.println("blend state -> " + newValue);
if (!newValue) {
// Whenever blending is disabled we trigger a change to the default blend function as well
// as vanilla assumes this to be the default when it's given that blending is off
changeFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
}
return true;
}

@Override
public boolean changeFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
if (srcRgb == blendState.srcRgb() && dstRgb == blendState.dstRgb() && srcAlpha == blendState.srcAlpha() && dstAlpha == blendState.dstAlpha()) return true;
// System.out.println("blend func -> " + srcRgb + ", " + dstRgb + ", " + srcAlpha + ", " + dstAlpha);
return true;
}

@Override
public void close() {
buffer.close();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.noxcrew.noxesium.feature.ui.render;

import com.noxcrew.noxesium.feature.ui.layer.NoxesiumLayeredDraw;
import com.noxcrew.noxesium.feature.ui.render.api.BlendState;
import com.noxcrew.noxesium.feature.ui.render.api.NoxesiumRenderState;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.gui.GuiGraphics;
Expand Down Expand Up @@ -93,6 +94,7 @@ public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker, NoxesiumL
// Tick the groups, possibly redrawing the buffer contents, if any buffers got drawn to
// we want to unbind the buffer afterwards
var bound = false;
var state = BlendState.standard();
for (var group : groups) {
// Determine if the group has recently changed their
// visibility state, if so request an immediate redraw!
Expand All @@ -104,7 +106,7 @@ public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker, NoxesiumL
}

// Update the dynamic element of the group
if (group.dynamic().update(nanoTime, guiGraphics, () -> {
if (group.dynamic().update(nanoTime, guiGraphics, state, () -> {
for (var layer : group.layers()) {
if (layer.group() == null || layer.group().test()) {
group.renderLayer(guiGraphics, deltaTracker, layer.layer(), layer.index());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
import com.mojang.blaze3d.vertex.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.noxcrew.noxesium.feature.CustomCoreShaders;
import com.noxcrew.noxesium.feature.ui.render.api.BlendState;
import com.noxcrew.noxesium.feature.ui.render.api.BlendStateHook;
import net.minecraft.client.Minecraft;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;

import java.io.Closeable;
import java.util.List;
Expand All @@ -25,12 +29,15 @@ public class SharedVertexBuffer implements Closeable {
private static final int MAX_SAMPLERS = 8;
private static final Matrix4f NULL_MATRIX = new Matrix4f();

// Controls whether changes in the OpenGL blending state a currently allowed
public static boolean allowBlendChanges = true;
// Sets a hook which controls the current blend state hook
public static BlendStateHook blendStateHook = null;

// Whether rebinding the current render target is allowed
public static boolean allowRebindingTarget = true;

// Set to true whenever the blend state is being cleared.
public static boolean ignoreBlendStateHook = false;

private static VertexBuffer buffer;
private static final AtomicBoolean configuring = new AtomicBoolean(false);

Expand Down Expand Up @@ -60,27 +67,16 @@ public static void draw(List<Integer> textureIds) {
RenderSystem.depthMask(false);

// Cache the current blend state so we can return to it
var blend = GlStateManager.BLEND.mode.enabled;
var srcRgb = GlStateManager.BLEND.srcRgb;
var dstRgb = GlStateManager.BLEND.dstRgb;
var srcAlpha = GlStateManager.BLEND.srcAlpha;
var dstAlpha = GlStateManager.BLEND.dstAlpha;

// Set up the blending properties (or re-use if possible)
if (!blend) {
RenderSystem.enableBlend();
}
if (srcRgb != GlStateManager.SourceFactor.ONE.value || dstRgb != GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA.value) {
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
}
var originalBlendState = BlendState.snapshot();

// Set up the default blending properties
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);

// Set up the correct shaders and color
var shader = Objects.requireNonNull(RenderSystem.setShader(CustomCoreShaders.BLIT_SCREEN_MULTIPLE), "Blit shader not loaded");
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);

// Prevent further blending changes
allowBlendChanges = false;

// Bind the vertex shader
SharedVertexBuffer.bind();

Expand Down Expand Up @@ -118,14 +114,8 @@ public static void draw(List<Integer> textureIds) {
RenderSystem.enableDepthTest();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);

// Restore the original state
allowBlendChanges = true;
if (blend) {
RenderSystem.enableBlend();
} else {
RenderSystem.disableBlend();
}
GlStateManager._blendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha);
// Restore the old blend state directly
originalBlendState.apply();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.noxcrew.noxesium.feature.ui.render.api;

import com.mojang.blaze3d.platform.GlStateManager;
import org.lwjgl.opengl.GL11;

/**
* Holds a snapshot of the current blending state.
*/
public class BlendState {

/**
* Returns the initial blend state before UI rendering starts in vanilla.
*/
public static BlendState initial() {
var state = new BlendState();
state.blend = false;
state.srcRgb = GL11.GL_SRC_ALPHA;
state.dstRgb = GL11.GL_ONE_MINUS_SRC_ALPHA;
state.srcAlpha = GL11.GL_ONE;
state.dstAlpha = GL11.GL_ZERO;
return state;
}

/**
* Returns the standard blend state when rendering UI elements.
*/
public static BlendState standard() {
var state = new BlendState();
state.blend = true;
state.srcRgb = GL11.GL_SRC_ALPHA;
state.dstRgb = GL11.GL_ONE_MINUS_SRC_ALPHA;
state.srcAlpha = GL11.GL_ONE;
state.dstAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA;
return state;
}

/**
* Takes a snapshot of the current blend state
* intended by vanilla.
*/
public static BlendState snapshot() {
var state = new BlendState();
state.blend = GlStateManager.BLEND.mode.enabled;
state.srcRgb = GlStateManager.BLEND.srcRgb;
state.dstRgb = GlStateManager.BLEND.dstRgb;
state.srcAlpha = GlStateManager.BLEND.srcAlpha;
state.dstAlpha = GlStateManager.BLEND.dstAlpha;
return state;
}

private boolean blend;
private int srcRgb, dstRgb, srcAlpha, dstAlpha;

/**
* Applies this blend state.
*/
public void apply() {
if (blend) {
GlStateManager._enableBlend();
} else {
GlStateManager._disableBlend();
}

GlStateManager._blendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha);
}

/**
* Returns whether blending is enabled.
*/
public boolean enabled() {
return blend;
}

/**
* Returns the srcRgb value.
*/
public int srcRgb() {
return srcRgb;
}

/**
* Returns the dstRgb value.
*/
public int dstRgb() {
return dstRgb;
}

/**
* Returns the srcAlpha value.
*/
public int srcAlpha() {
return srcAlpha;
}

/**
* Returns the dstAlpha value.
*/
public int dstAlpha() {
return dstAlpha;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.noxcrew.noxesium.feature.ui.render.api;

/**
* A hook that receives any changes to the blending state.
*/
public interface BlendStateHook {

/**
* Called when the blending state is attempted to
* be changed to [newValue]. If `true` is returned
* the call is prevented.
*/
boolean changeState(boolean newValue);

/**
* Called when the blending function is attempted to
* be changed to the new values. If `true` is returned
* the call is prevented.
*/
boolean changeFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.noxcrew.noxesium.feature.ui.render.DynamicElement;
import com.noxcrew.noxesium.feature.ui.render.SharedVertexBuffer;
import com.noxcrew.noxesium.feature.ui.render.api.BlendState;
import com.noxcrew.noxesium.feature.ui.render.api.NoxesiumRenderState;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.Screen;
Expand Down Expand Up @@ -36,7 +37,8 @@ public void render(GuiGraphics guiGraphics, int width, int height, float deltaTi
}

// Update the buffer and redraw it if necessary
if (dynamic.update(nanoTime, guiGraphics, () -> screen.renderWithTooltip(guiGraphics, width, height, deltaTime))) {
var blendState = BlendState.standard();
if (dynamic.update(nanoTime, guiGraphics, blendState, () -> screen.renderWithTooltip(guiGraphics, width, height, deltaTime))) {
SharedVertexBuffer.rebindMainRenderTarget();
}

Expand Down
Loading

0 comments on commit ab81b34

Please sign in to comment.