mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 01:34:48 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c5e5df290 | ||
|
|
39ee364418 | ||
|
|
4c9cae5e0b | ||
|
|
11b53c9f8f | ||
|
|
c769a08a4e | ||
|
|
90dac9f39d | ||
|
|
c5c4b290b1 | ||
|
|
4b46de4566 | ||
|
|
9f2a71be4e | ||
|
|
79fe08417c | ||
|
|
5de64abdef | ||
|
|
2e07465166 | ||
|
|
2b610b9aea | ||
|
|
ab192ddd2a |
No files matched your search
+2
-2
@@ -82,8 +82,8 @@ dependencies {
|
||||
compileOnly "org.apache.ant:ant:1.8.2"
|
||||
|
||||
// Celeritas (transitive=false: deps provided by GTNHLib/runtime)
|
||||
embedOnly("org.embeddedt.celeritas:celeritas-common:2.5.2-GTNH") { transitive = false }
|
||||
embedOnly("org.embeddedt.celeritas:celeritas-lwjgl2-service:2.5.2-GTNH") { transitive = false }
|
||||
embedOnly("org.embeddedt.celeritas:celeritas-common:2.5.3-GTNH") { transitive = false }
|
||||
embedOnly("org.embeddedt.celeritas:celeritas-lwjgl2-service:2.5.3-GTNH") { transitive = false }
|
||||
|
||||
// Because who doesn't want NEI
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.8.35-GTNH:dev')
|
||||
|
||||
@@ -6,24 +6,26 @@ import com.gtnewhorizon.gtnhlib.client.renderer.vao.IndexBuffer;
|
||||
import com.gtnewhorizon.gtnhlib.util.font.GlyphReplacements;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.Setter;
|
||||
import net.coderbot.iris.gl.program.Program;
|
||||
import net.coderbot.iris.gl.program.ProgramBuilder;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.embeddedt.embeddium.impl.render.shader.ShaderLoader;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -57,21 +59,18 @@ public class BatchingFontRenderer {
|
||||
final boolean isSGA;
|
||||
final boolean isSplash;
|
||||
|
||||
/** For use with modded books. Affects calculations and forces some defaults. */
|
||||
@Setter
|
||||
boolean bookMode = false;
|
||||
|
||||
private static class FontAAShader {
|
||||
|
||||
private static Program fontShader = null;
|
||||
public static Program getProgram() {
|
||||
if (fontShader == null) {
|
||||
String vsh, fsh;
|
||||
try {
|
||||
fsh = new String(IOUtils.toByteArray(Objects.requireNonNull(FontAAShader.class.getResourceAsStream("/assets/angelica/shaders/fontFilter.fsh"))), StandardCharsets.UTF_8);
|
||||
vsh = new String(IOUtils.toByteArray(Objects.requireNonNull(FontAAShader.class.getResourceAsStream("/assets/angelica/shaders/fontFilter.vsh"))), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
ProgramBuilder builder = ProgramBuilder.begin("fontFilter", vsh, null, fsh, ImmutableSet.of(0));
|
||||
fontShader = builder.build();
|
||||
final String vsh = ShaderLoader.getShaderSource("angelica:fontFilter.vsh");
|
||||
final String fsh = ShaderLoader.getShaderSource("angelica:fontFilter.fsh");
|
||||
fontShader = ProgramBuilder.begin("fontFilter", vsh, null, fsh, ImmutableSet.of(0)).build();
|
||||
}
|
||||
return fontShader;
|
||||
}
|
||||
@@ -116,7 +115,10 @@ public class BatchingFontRenderer {
|
||||
// v, t and tb are floats, c is bytes; 36 bytes total
|
||||
private static final int VERTEX_SIZE = 36;
|
||||
private static int rawCapacity = INITIAL_BATCH_SIZE * VERTEX_SIZE;
|
||||
private static long vertexDataAddress = nmemAllocChecked(rawCapacity);
|
||||
private static ByteBuffer vertexData = memAlloc(rawCapacity);
|
||||
private static long vertexDataAddress = memAddress0(vertexData);
|
||||
private static int vboCapacity;
|
||||
|
||||
|
||||
// OpenGL objects (static, can be used between multiple BatchingFontRenderer)
|
||||
private static int fontVAO = 0;
|
||||
@@ -167,7 +169,8 @@ public class BatchingFontRenderer {
|
||||
private void ensureCapacity() {
|
||||
if (vertexDataPos + (4 * VERTEX_SIZE) > rawCapacity) {
|
||||
rawCapacity *= 2;
|
||||
vertexDataAddress = nmemReallocChecked(vertexDataAddress, rawCapacity);
|
||||
vertexData = memRealloc(vertexData, rawCapacity);
|
||||
vertexDataAddress = memAddress0(vertexData);
|
||||
|
||||
allocateBuffers();
|
||||
}
|
||||
@@ -321,8 +324,8 @@ public class BatchingFontRenderer {
|
||||
|
||||
// Upload first (to reduce stalls)
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
|
||||
|
||||
streamUpload(vertexDataAddress, vertexDataPos);
|
||||
vertexData.limit(vertexDataPos);
|
||||
vboCapacity = StreamingUploader.upload(vertexData, vboCapacity);
|
||||
|
||||
final int prevProgram = GLStateManager.glGetInteger(GL20.GL_CURRENT_PROGRAM);
|
||||
|
||||
@@ -427,12 +430,6 @@ public class BatchingFontRenderer {
|
||||
idxWriterIndex = 0;
|
||||
}
|
||||
|
||||
private static void streamUpload(long address, int bytes) {
|
||||
final ByteBuffer data = memByteBuffer(address, bytes);
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, bytes, GL15.GL_STREAM_DRAW);
|
||||
GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, data);
|
||||
}
|
||||
|
||||
// === Actual text mesh generation
|
||||
|
||||
public static boolean charInRange(char what, char fromInclusive, char toInclusive) {
|
||||
@@ -440,7 +437,7 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
|
||||
public boolean forceDefaults() {
|
||||
return this.isSGA || this.isSplash;
|
||||
return this.bookMode || this.isSGA || this.isSplash;
|
||||
}
|
||||
|
||||
public float getGlyphScaleX() {
|
||||
@@ -596,7 +593,7 @@ public class BatchingFontRenderer {
|
||||
|
||||
// Check ASCII space, NBSP, NNBSP
|
||||
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
|
||||
curX += 4 * this.getWhitespaceScale();
|
||||
curX += 4 * this.getWhitespaceScale() + (curBold ? 1 : 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -646,7 +643,8 @@ public class BatchingFontRenderer {
|
||||
final int vtxCount = 4 * charCount;
|
||||
pushDrawCmd(idxId, vtxCount / 2 * 3, texture, chr > 255);
|
||||
|
||||
curX += (xAdvance + (curBold ? shadowOffset : 0.0f)) + getGlyphSpacing();
|
||||
curX += (xAdvance + (curBold ? 1.0f : 0.0f)) + getGlyphSpacing();
|
||||
if (bookMode) { curX = (int) curX; }
|
||||
underlineEndX = curX;
|
||||
strikethroughEndX = curX;
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public final class FontProviderUnicode implements FontProvider {
|
||||
|
||||
@Override
|
||||
public float getShadowOffset() {
|
||||
return FontConfig.fontShadowOffset;
|
||||
return FontConfig.fontShadowOffset * FontConfig.fontShadowOffsetUC;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -75,13 +75,16 @@ public class FontStrategist {
|
||||
}
|
||||
|
||||
/**
|
||||
Lets you get a FontProvider per char while respecting font priority and fallbacks, the unicode flag, whether or not
|
||||
Lets you get a FontProvider per char while respecting font priority and fallbacks, the unicode flag, whether
|
||||
SGA is on, if we're in a splash screen, if a font can even display a character in the first place, etc.
|
||||
*/
|
||||
public static FontProvider getFontProvider(BatchingFontRenderer me, char chr, boolean customFontEnabled, boolean forceUnicode) {
|
||||
if (me.isSGA && FontProviderMC.get(true).isGlyphAvailable(chr)) {
|
||||
return FontProviderMC.get(true);
|
||||
}
|
||||
if (me.bookMode) {
|
||||
return FontProviderUnicode.get();
|
||||
}
|
||||
if (customFontEnabled && !me.isSplash) {
|
||||
FontProvider fp;
|
||||
fp = FontProviderCustom.getPrimary();
|
||||
|
||||
@@ -38,7 +38,7 @@ public class FontConfigScreen extends GuiScreen {
|
||||
private ArrayList<Font> displayedFonts;
|
||||
private GuiTextField searchBox;
|
||||
private GuiTextField testArea;
|
||||
private int sliderPages = 0;
|
||||
private int lastSliderPageIndex = 0;
|
||||
private int displayedSliderPage = 0;
|
||||
private final int sliderWidth = 160;
|
||||
private final int sliderHeight = 20;
|
||||
@@ -58,6 +58,7 @@ public class FontConfigScreen extends GuiScreen {
|
||||
SliderClone.Option optFontAAMode = new SliderClone.Option(0, 2, 1);
|
||||
SliderClone.Option optFontAAStrength = new SliderClone.Option(1, 24, 1);
|
||||
SliderClone.Option optCustomFontScale = new SliderClone.Option(0.1f, 3, 0.05f);
|
||||
SliderClone.Option optShadowOffsetUC = new SliderClone.Option(0, 2, 0.05f);
|
||||
|
||||
public FontConfigScreen(GuiScreen parent) {
|
||||
this.title = I18n.format("options.angelica.fontconfig.title");
|
||||
@@ -226,6 +227,16 @@ public class FontConfigScreen extends GuiScreen {
|
||||
.formatString("x%3.2f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optShadowOffsetUC)
|
||||
.initialValue(FontConfig.fontShadowOffsetUC)
|
||||
.setter(value -> FontConfig.fontShadowOffsetUC = value)
|
||||
.langKey("options.angelica.fontconfig.shadow_offset_unicode")
|
||||
.formatString("x%3.2f")
|
||||
.build()
|
||||
);
|
||||
|
||||
final int halfWidth = this.width / 2;
|
||||
final int sliderSpacing = 4;
|
||||
@@ -236,11 +247,11 @@ public class FontConfigScreen extends GuiScreen {
|
||||
final int y1 = this.height - 65;
|
||||
final int y2 = this.height - 65 + sliderHeight + sliderSpacing;
|
||||
|
||||
this.sliderPages = sliders.size() / 6;
|
||||
this.displayedSliderPage = Math.min(this.displayedSliderPage, this.sliderPages);
|
||||
this.lastSliderPageIndex = (sliders.size() - 1) / 6;
|
||||
this.displayedSliderPage = Math.min(this.displayedSliderPage, this.lastSliderPageIndex);
|
||||
|
||||
this.backButton.enabled = (this.displayedSliderPage != 0);
|
||||
this.fwdButton.enabled = (this.displayedSliderPage != this.sliderPages);
|
||||
this.fwdButton.enabled = (this.displayedSliderPage != this.lastSliderPageIndex);
|
||||
|
||||
final int start = 6 * this.displayedSliderPage;
|
||||
final int end = Math.min(6 * (this.displayedSliderPage + 1), sliders.size());
|
||||
@@ -304,7 +315,7 @@ public class FontConfigScreen extends GuiScreen {
|
||||
}
|
||||
|
||||
private void switchPage(int offset) {
|
||||
this.displayedSliderPage = MathHelper.clamp_int(this.displayedSliderPage + offset, 0, this.sliderPages);
|
||||
this.displayedSliderPage = MathHelper.clamp_int(this.displayedSliderPage + offset, 0, this.lastSliderPageIndex);
|
||||
this.buttonList.removeIf(guiButton -> guiButton instanceof SliderClone);
|
||||
this.initSliders();
|
||||
}
|
||||
|
||||
@@ -71,6 +71,11 @@ public class FontConfig {
|
||||
@Config.RangeFloat(min = 0.1F, max = 3F)
|
||||
public static float customFontScale;
|
||||
|
||||
@Config.Comment("A shadow offset multiplier applied only to the Unicode font.")
|
||||
@Config.DefaultFloat(0.5F)
|
||||
@Config.RangeFloat(min = 0F, max = 2F)
|
||||
public static float fontShadowOffsetUC;
|
||||
|
||||
@Config.Comment({"Mods can provide Angelica with a mapping of special characters to either get replaced with " +
|
||||
"different characters or rendered using the default Unicode font. Setting this to false disables the " +
|
||||
"replacement, which is useful in cases where custom fonts have direct support for these special characters. ",
|
||||
|
||||
@@ -40,7 +40,7 @@ import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
|
||||
public class CompatShaderTransformer {
|
||||
|
||||
private static final Pattern VERSION_PATTERN =
|
||||
Pattern.compile("#version\\s+(\\d+)(?:\\s+(\\w+))?");
|
||||
Pattern.compile("#version[ \\t]+(\\d+)(?:[ \\t]+(\\w+))?");
|
||||
|
||||
private static final Pattern DEFINE_PATTERN =
|
||||
Pattern.compile("^\\s*#\\s*define\\s+.+$", Pattern.MULTILINE);
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.gtnewhorizon.gtnhlib.client.renderer.DirectTessellator;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.stacks.IStateStack;
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.glsm.DisplayListManager.RecordMode;
|
||||
import com.gtnewhorizons.angelica.render.SelectionBoxRenderer;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.TessellatorStreamingDrawer;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CompiledDisplayList;
|
||||
@@ -583,6 +584,7 @@ public class GLStateManager {
|
||||
GL30.glBindVertexArray(defaultVAO);
|
||||
boundVAO = defaultVAO;
|
||||
VertexAttribState.init(defaultVAO);
|
||||
SelectionBoxRenderer.init();
|
||||
|
||||
// Drain any pending GL errors from initialization. In core profile, some legacy queries may generate GL_INVALID_ENUM. The splash thread inherits the
|
||||
// DrawableGL context and its error state, so stale errors here would cause SplashProgress.checkGLError() to fail.
|
||||
@@ -1713,7 +1715,18 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static int changeFormatIfDeprecated(int internalformat) {
|
||||
switch (internalformat) {
|
||||
case GL11.GL_ALPHA4 -> internalformat = GL11.GL_RGBA4;
|
||||
case GL11.GL_ALPHA8 -> internalformat = GL11.GL_RGBA8;
|
||||
case GL11.GL_ALPHA12 -> internalformat = GL11.GL_RGBA12;
|
||||
case GL11.GL_ALPHA16 -> internalformat = GL11.GL_RGBA16;
|
||||
}
|
||||
return internalformat;
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
DisplayListManager.recordComplexCommand(TexImage2DCmd.fromIntBuffer(target, level, internalformat, width, height, border, format, type, pixels));
|
||||
@@ -1732,6 +1745,7 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, FloatBuffer pixels) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
DisplayListManager.recordComplexCommand(TexImage2DCmd.fromFloatBuffer(target, level, internalformat, width, height, border, format, type, pixels));
|
||||
@@ -1745,6 +1759,7 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, DoubleBuffer pixels) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
DisplayListManager.recordComplexCommand(TexImage2DCmd.fromDoubleBuffer(target, level, internalformat, width, height, border, format, type, pixels));
|
||||
@@ -1758,6 +1773,7 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
DisplayListManager.recordComplexCommand(TexImage2DCmd.fromByteBuffer(target, level, internalformat, width, height, border, format, type, pixels));
|
||||
@@ -1776,6 +1792,7 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, long pixels_buffer_offset) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
if (DisplayListManager.isRecording()) {
|
||||
throw new UnsupportedOperationException("glTexImage2D with buffer offset in display lists not yet supported");
|
||||
}
|
||||
@@ -2032,6 +2049,12 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void glVertex2i(int x, int y) {
|
||||
if (DisplayListManager.isRecording() || ImmediateModeRecorder.isDrawing()) {
|
||||
ImmediateModeRecorder.vertex((float) x, (float) y, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glVertex2d(double x, double y) {
|
||||
if (DisplayListManager.isRecording() || ImmediateModeRecorder.isDrawing()) {
|
||||
ImmediateModeRecorder.vertex((float) x, (float) y, 0.0f);
|
||||
@@ -2049,6 +2072,13 @@ public class GLStateManager {
|
||||
ImmediateModeRecorder.vertex((float) x, (float) y, (float) z);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glVertex3i(int x, int y, int z) {
|
||||
if (DisplayListManager.isRecording() || ImmediateModeRecorder.isDrawing()) {
|
||||
ImmediateModeRecorder.vertex((float) x, (float) y, (float) z);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, ByteBuffer indices) {
|
||||
if (DisplayListManager.isRecording()) {
|
||||
throw new UnsupportedOperationException("glDrawElements in display lists not yet implemented - if you see this, please report!");
|
||||
@@ -2310,6 +2340,10 @@ public class GLStateManager {
|
||||
GL20.glVertexAttribPointer(index, size, type, normalized, stride, offset);
|
||||
}
|
||||
|
||||
public static void glVertexAttribPointer(int index, int size, boolean normalized, int stride, FloatBuffer pointer) {
|
||||
glVertexAttribPointer(index, size, GL11.GL_FLOAT, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
public static void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, FloatBuffer pointer) {
|
||||
final ByteBuffer bb = MemoryUtilities.memByteBuffer(pointer);
|
||||
VertexAttribState.set(index, size, type, normalized, stride, bb, boundVBO);
|
||||
@@ -4005,6 +4039,7 @@ public class GLStateManager {
|
||||
|
||||
// Missing GL commands from Mesa cross-check
|
||||
public static void glTexImage1D(int target, int level, int internalformat, int width, int border, int format, int type, ByteBuffer pixels) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
if (DisplayListManager.isRecording()) {
|
||||
throw new UnsupportedOperationException("glTexImage1D in display lists not yet implemented");
|
||||
}
|
||||
@@ -4012,6 +4047,15 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glTexImage3D(int target, int level, int internalformat, int width, int height, int depth, int border, int format, int type, ByteBuffer pixels) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
if (DisplayListManager.isRecording()) {
|
||||
throw new UnsupportedOperationException("glTexImage3D in display lists not yet implemented");
|
||||
}
|
||||
GL12.glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels);
|
||||
}
|
||||
|
||||
public static void glTexImage3D(int target, int level, int internalformat, int width, int height, int depth, int border, int format, int type, IntBuffer pixels) {
|
||||
internalformat = changeFormatIfDeprecated(internalformat);
|
||||
if (DisplayListManager.isRecording()) {
|
||||
throw new UnsupportedOperationException("glTexImage3D in display lists not yet implemented");
|
||||
}
|
||||
@@ -4921,6 +4965,62 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static float glGetTexEnvf(int target, int pname) {
|
||||
return (float) glGetTexEnvi(target, pname);
|
||||
}
|
||||
|
||||
public static int glGetTexEnvi(int target, int pname) {
|
||||
if (target != GL11.GL_TEXTURE_ENV) return 0;
|
||||
|
||||
final var envState = textures.getTexEnvState(activeTextureUnit.getValue());
|
||||
return switch (pname) {
|
||||
case GL11.GL_TEXTURE_ENV_MODE -> envState.mode;
|
||||
case GL13.GL_COMBINE_RGB -> envState.combineRgb;
|
||||
case GL13.GL_COMBINE_ALPHA -> envState.combineAlpha;
|
||||
case GL13.GL_SOURCE0_RGB -> envState.sourceRgb[0];
|
||||
case GL13.GL_SOURCE1_RGB -> envState.sourceRgb[1];
|
||||
case GL13.GL_SOURCE2_RGB -> envState.sourceRgb[2];
|
||||
case GL13.GL_SOURCE0_ALPHA -> envState.sourceAlpha[0];
|
||||
case GL13.GL_SOURCE1_ALPHA -> envState.sourceAlpha[1];
|
||||
case GL13.GL_SOURCE2_ALPHA -> envState.sourceAlpha[2];
|
||||
case GL13.GL_OPERAND0_RGB -> envState.operandRgb[0];
|
||||
case GL13.GL_OPERAND1_RGB -> envState.operandRgb[1];
|
||||
case GL13.GL_OPERAND2_RGB -> envState.operandRgb[2];
|
||||
case GL13.GL_OPERAND0_ALPHA -> envState.operandAlpha[0];
|
||||
case GL13.GL_OPERAND1_ALPHA -> envState.operandAlpha[1];
|
||||
case GL13.GL_OPERAND2_ALPHA -> envState.operandAlpha[2];
|
||||
case GL13.GL_RGB_SCALE -> (int) envState.scaleRgb;
|
||||
case GL11.GL_ALPHA_SCALE -> (int) envState.scaleAlpha;
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
public static void glGetTexEnv(int target, int pname, IntBuffer params) {
|
||||
if (target != GL11.GL_TEXTURE_ENV) return;
|
||||
if (pname == GL11.GL_TEXTURE_ENV_COLOR) {
|
||||
final var envState = textures.getTexEnvState(activeTextureUnit.getValue());
|
||||
params.put(params.position(), (int) (envState.envColorR * 2147483647.0f));
|
||||
params.put(params.position() + 1, (int) (envState.envColorG * 2147483647.0f));
|
||||
params.put(params.position() + 2, (int) (envState.envColorB * 2147483647.0f));
|
||||
params.put(params.position() + 3, (int) (envState.envColorA * 2147483647.0f));
|
||||
} else {
|
||||
params.put(params.position(), glGetTexEnvi(target, pname));
|
||||
}
|
||||
}
|
||||
|
||||
public static void glGetTexEnv(int target, int pname, FloatBuffer params) {
|
||||
if (target != GL11.GL_TEXTURE_ENV) return;
|
||||
if (pname == GL11.GL_TEXTURE_ENV_COLOR) {
|
||||
final var envState = textures.getTexEnvState(activeTextureUnit.getValue());
|
||||
params.put(params.position(), envState.envColorR);
|
||||
params.put(params.position() + 1, envState.envColorG);
|
||||
params.put(params.position() + 2, envState.envColorB);
|
||||
params.put(params.position() + 3, envState.envColorA);
|
||||
} else {
|
||||
params.put(params.position(), (float) glGetTexEnvi(target, pname));
|
||||
}
|
||||
}
|
||||
|
||||
// TexGen generation counter for FFP uniform dirty tracking
|
||||
public static int texGenGeneration;
|
||||
|
||||
@@ -5007,6 +5107,65 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static int glGetTexGeni(int coord, int pname) {
|
||||
if (pname == GL11.GL_TEXTURE_GEN_MODE) {
|
||||
return textures.getTexGenState(activeTextureUnit.getValue()).getMode(coord);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static float glGetTexGenf(int coord, int pname) {
|
||||
return (float) glGetTexGeni(coord, pname);
|
||||
}
|
||||
|
||||
public static double glGetTexGend(int coord, int pname) {
|
||||
return glGetTexGeni(coord, pname);
|
||||
}
|
||||
|
||||
public static void glGetTexGen(int coord, int pname, IntBuffer params) {
|
||||
if (pname == GL11.GL_TEXTURE_GEN_MODE) {
|
||||
params.put(params.position(), glGetTexGeni(coord, pname));
|
||||
}
|
||||
}
|
||||
|
||||
public static void glGetTexGen(int coord, int pname, FloatBuffer params) {
|
||||
final var state = textures.getTexGenState(activeTextureUnit.getValue());
|
||||
if (pname == GL11.GL_TEXTURE_GEN_MODE) {
|
||||
params.put(params.position(), (float) state.getMode(coord));
|
||||
} else if (pname == GL11.GL_OBJECT_PLANE) {
|
||||
final float[] plane = state.getObjectPlane(coord);
|
||||
params.put(params.position(), plane[0]);
|
||||
params.put(params.position() + 1, plane[1]);
|
||||
params.put(params.position() + 2, plane[2]);
|
||||
params.put(params.position() + 3, plane[3]);
|
||||
} else if (pname == GL11.GL_EYE_PLANE) {
|
||||
final float[] plane = state.getEyePlane(coord);
|
||||
params.put(params.position(), plane[0]);
|
||||
params.put(params.position() + 1, plane[1]);
|
||||
params.put(params.position() + 2, plane[2]);
|
||||
params.put(params.position() + 3, plane[3]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glGetTexGen(int coord, int pname, DoubleBuffer params) {
|
||||
final var state = textures.getTexGenState(activeTextureUnit.getValue());
|
||||
if (pname == GL11.GL_TEXTURE_GEN_MODE) {
|
||||
params.put(params.position(), state.getMode(coord));
|
||||
} else if (pname == GL11.GL_OBJECT_PLANE) {
|
||||
final float[] plane = state.getObjectPlane(coord);
|
||||
params.put(params.position(), plane[0]);
|
||||
params.put(params.position() + 1, plane[1]);
|
||||
params.put(params.position() + 2, plane[2]);
|
||||
params.put(params.position() + 3, plane[3]);
|
||||
} else if (pname == GL11.GL_EYE_PLANE) {
|
||||
final float[] plane = state.getEyePlane(coord);
|
||||
params.put(params.position(), plane[0]);
|
||||
params.put(params.position() + 1, plane[1]);
|
||||
params.put(params.position() + 2, plane[2]);
|
||||
params.put(params.position() + 3, plane[3]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glPolygonStipple(ByteBuffer pattern) {
|
||||
guardUnsupportedFFP("glPolygonStipple", "glPolygonStipple is not available in GL 3.3 core profile.");
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@ import com.gtnewhorizon.gtnhlib.client.renderer.DirectTessellator;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.QuadConverter;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.OrphanStreamingBuffer;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.OrphanStreamingBuffer.UploadStrategy;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.PersistentStreamingBuffer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -47,7 +45,6 @@ public class TessellatorStreamingDrawer {
|
||||
private static int repackCapacity;
|
||||
|
||||
private static boolean initialized = false;
|
||||
private static UploadStrategy orphanStrategy = UploadStrategy.BUFFER_SUB_DATA;
|
||||
|
||||
static {
|
||||
// Initial repack buffer: 64KB
|
||||
@@ -60,12 +57,6 @@ public class TessellatorStreamingDrawer {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
// Select orphan upload strategy from config
|
||||
if (AngelicaMod.options() != null && AngelicaMod.options().advanced.useMapBufferRange) {
|
||||
orphanStrategy = UploadStrategy.MAP_BUFFER_RANGE;
|
||||
}
|
||||
LOGGER.info("Orphan upload strategy: {}", orphanStrategy);
|
||||
|
||||
if (RenderSystem.supportsBufferStorage() && !Boolean.getBoolean("angelica.forceOrphanStreaming")) {
|
||||
try {
|
||||
persistentBuffer = new PersistentStreamingBuffer();
|
||||
@@ -179,11 +170,6 @@ public class TessellatorStreamingDrawer {
|
||||
if (persistentBuffer != null) {
|
||||
persistentBuffer.postDraw();
|
||||
}
|
||||
for (int i = 0; i < FORMAT_COUNT; i++) {
|
||||
if (orphanBuffers[i] != null) {
|
||||
orphanBuffers[i].postDraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,7 +217,8 @@ public class TessellatorStreamingDrawer {
|
||||
GLStateManager.glBindVertexArray(persistentVAOs[flags]);
|
||||
} else {
|
||||
GLStateManager.glBindVertexArray(orphanVAOs[flags]);
|
||||
firstVertex = orphanBuffers[flags].upload(packed, vertexSize);
|
||||
orphanBuffers[flags].upload(packed);
|
||||
firstVertex = 0;
|
||||
}
|
||||
|
||||
GLStateManager.prepareWideLineEmulation(drawMode);
|
||||
@@ -266,7 +253,7 @@ public class TessellatorStreamingDrawer {
|
||||
init();
|
||||
|
||||
if (orphanVAOs[flags] == 0) {
|
||||
orphanBuffers[flags] = new OrphanStreamingBuffer(orphanStrategy);
|
||||
orphanBuffers[flags] = new OrphanStreamingBuffer();
|
||||
|
||||
orphanVAOs[flags] = GL30.glGenVertexArrays();
|
||||
GLStateManager.glBindVertexArray(orphanVAOs[flags]);
|
||||
|
||||
+8
-102
@@ -1,142 +1,48 @@
|
||||
package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCopy;
|
||||
import static com.mitchej123.lwjgl.LWJGLServiceProvider.LWJGL;
|
||||
|
||||
/**
|
||||
* Streaming buffer using the classic orphan pattern with sub-allocation.
|
||||
* <p>
|
||||
* Supports two upload strategies:
|
||||
* <ul>
|
||||
* <li>{@link UploadStrategy#BUFFER_SUB_DATA} — glBufferData orphan + glBufferSubData (default)</li>
|
||||
* <li>{@link UploadStrategy#MAP_BUFFER_RANGE} — glMapBufferRange with INVALIDATE hints </li>
|
||||
* </ul>
|
||||
* Streaming buffer using the classic orphan pattern.
|
||||
*/
|
||||
public class OrphanStreamingBuffer implements StreamingBuffer {
|
||||
|
||||
public enum UploadStrategy {
|
||||
BUFFER_SUB_DATA,
|
||||
MAP_BUFFER_RANGE
|
||||
}
|
||||
|
||||
private static final int MAP_WRITE_INVALIDATE_BUFFER = GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_BUFFER_BIT | GL30.GL_MAP_UNSYNCHRONIZED_BIT;
|
||||
private static final int MAP_WRITE_INVALIDATE_RANGE = GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT | GL30.GL_MAP_UNSYNCHRONIZED_BIT;
|
||||
public final class OrphanStreamingBuffer {
|
||||
|
||||
private int bufferId;
|
||||
private int capacity;
|
||||
private int writePos;
|
||||
private boolean needsOrphan = true;
|
||||
private final UploadStrategy strategy;
|
||||
|
||||
public OrphanStreamingBuffer() {
|
||||
this(UploadStrategy.BUFFER_SUB_DATA);
|
||||
}
|
||||
|
||||
public OrphanStreamingBuffer(UploadStrategy strategy) {
|
||||
this.strategy = strategy;
|
||||
this.bufferId = GL15.glGenBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int upload(ByteBuffer data, int vertexStride) {
|
||||
final int dataSize = data.remaining();
|
||||
|
||||
final int alignUnit = vertexStride * 4;
|
||||
int alignedPos = ((writePos + alignUnit - 1) / alignUnit) * alignUnit;
|
||||
|
||||
public void upload(ByteBuffer data) {
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferId);
|
||||
|
||||
boolean freshAllocation = false;
|
||||
if (alignedPos + dataSize > capacity) {
|
||||
// Doesn't fit — grow if needed, allocate new storage, reset to offset 0
|
||||
growIfNeeded(dataSize);
|
||||
allocateBuffer();
|
||||
alignedPos = 0;
|
||||
freshAllocation = true;
|
||||
} else if (needsOrphan) {
|
||||
// First upload of the frame — need fresh storage
|
||||
if (strategy == UploadStrategy.BUFFER_SUB_DATA) {
|
||||
// SubData strategy: orphan via glBufferData to get new backing store
|
||||
allocateBuffer();
|
||||
}
|
||||
}
|
||||
if (strategy == UploadStrategy.BUFFER_SUB_DATA) {
|
||||
GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, alignedPos, data);
|
||||
} else {
|
||||
// MapRange: choose flags based on whether this is the first upload of the frame
|
||||
final int flags;
|
||||
if (freshAllocation) {
|
||||
// Fresh allocation — nothing to invalidate, just write
|
||||
flags = MAP_WRITE_INVALIDATE_RANGE;
|
||||
} else if (needsOrphan) {
|
||||
// First upload of frame on existing buffer — invalidate entire buffer
|
||||
flags = MAP_WRITE_INVALIDATE_BUFFER;
|
||||
} else {
|
||||
// Subsequent upload — invalidate only our range
|
||||
flags = MAP_WRITE_INVALIDATE_RANGE;
|
||||
}
|
||||
final ByteBuffer mapped = LWJGL.glMapBufferRange(GL15.GL_ARRAY_BUFFER, alignedPos, dataSize, flags);
|
||||
memCopy(memAddress0(data), memAddress0(mapped), dataSize);
|
||||
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
|
||||
}
|
||||
capacity = StreamingUploader.upload(data, capacity);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
needsOrphan = false;
|
||||
writePos = alignedPos + dataSize;
|
||||
return alignedPos / vertexStride;
|
||||
}
|
||||
|
||||
private static final int MIN_CAPACITY = 64 * 1024;
|
||||
|
||||
private void growIfNeeded(int needed) {
|
||||
if (needed > capacity) {
|
||||
int newCapacity = Math.max(capacity, MIN_CAPACITY);
|
||||
while (newCapacity < needed) {
|
||||
newCapacity *= 2;
|
||||
}
|
||||
capacity = newCapacity;
|
||||
}
|
||||
void upload(StreamingUploader.UploadStrategy strategy, ByteBuffer data) {
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferId);
|
||||
capacity = StreamingUploader.upload(strategy, data, capacity);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
private void allocateBuffer() {
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, capacity, GL15.GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferId() {
|
||||
return bufferId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDraw() {
|
||||
writePos = 0;
|
||||
needsOrphan = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (bufferId != 0) {
|
||||
GL15.glDeleteBuffers(bufferId);
|
||||
bufferId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int getWritePos() {
|
||||
return writePos;
|
||||
}
|
||||
|
||||
UploadStrategy getStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.NamedState;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCopy;
|
||||
import static com.mitchej123.lwjgl.LWJGLServiceProvider.LWJGL;
|
||||
|
||||
public final class StreamingUploader {
|
||||
|
||||
public enum UploadStrategy implements NamedState {
|
||||
BUFFER_DATA("sodium.options.upload_method.buffer_data"),
|
||||
BUFFER_SUB_DATA("sodium.options.upload_method.buffer_subdata"),
|
||||
MAP_BUFFER_RANGE("sodium.options.upload_method.map_buffer");
|
||||
|
||||
|
||||
private final String key;
|
||||
|
||||
UploadStrategy(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MAP_WRITE_INVALIDATE_BUFFER = GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_BUFFER_BIT;
|
||||
|
||||
public static int upload(ByteBuffer data, int capacity) {
|
||||
return upload(AngelicaMod.options().advanced.streamingUploadStrategy, data, capacity);
|
||||
}
|
||||
|
||||
public static int upload(UploadStrategy strategy, ByteBuffer data, int capacity) {
|
||||
switch (strategy) {
|
||||
case BUFFER_DATA -> {
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
return data.remaining();
|
||||
}
|
||||
case BUFFER_SUB_DATA -> {
|
||||
if (data.remaining() > capacity) {
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
return data.remaining();
|
||||
}
|
||||
GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, data);
|
||||
return capacity;
|
||||
}
|
||||
case MAP_BUFFER_RANGE -> {
|
||||
if (data.remaining() > capacity) {
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
return data.remaining();
|
||||
}
|
||||
final int dataSize = data.remaining();
|
||||
final ByteBuffer mapped = LWJGL.glMapBufferRange(GL15.GL_ARRAY_BUFFER, 0, dataSize, MAP_WRITE_INVALIDATE_BUFFER);
|
||||
memCopy(memAddress0(data), memAddress0(mapped), dataSize);
|
||||
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
|
||||
return capacity;
|
||||
}
|
||||
default -> throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,15 @@ public class AngelicaLateTweaker implements ITweaker {
|
||||
exceptions.add("Reika.DragonAPI.ASM.StructureLootHooks");
|
||||
FMLRelaunchLog.info("[Angelica] Narrowed Reika.DragonAPI.ASM transformer exclusion to allow GL redirection of utility classes");
|
||||
}
|
||||
|
||||
if (exceptions.remove("xaero.common.core")) {
|
||||
exceptions.add("xaero.common.core.transformer");
|
||||
FMLRelaunchLog.info("[Angelica] Narrowed xaero.common.core transformer exclusion to allow GL redirection");
|
||||
}
|
||||
if (exceptions.remove("xaero.map.core")) {
|
||||
exceptions.add("xaero.map.core.transformer");
|
||||
FMLRelaunchLog.info("[Angelica] Narrowed xaero.map.core transformer exclusion to allow GL redirection");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FMLRelaunchLog.warning("[Angelica] Failed to narrow transformer exclusions: %s", e.getMessage());
|
||||
}
|
||||
|
||||
+9
@@ -185,10 +185,17 @@ public final class AngelicaRedirector {
|
||||
.add("glTexEnvi")
|
||||
.add("glTexEnvf")
|
||||
.add("glTexEnv")
|
||||
.add("glGetTexEnv")
|
||||
.add("glGetTexEnvi")
|
||||
.add("glGetTexEnvf")
|
||||
.add("glTexGeni")
|
||||
.add("glTexGenf")
|
||||
.add("glTexGend")
|
||||
.add("glTexGen")
|
||||
.add("glGetTexGen")
|
||||
.add("glGetTexGeni")
|
||||
.add("glGetTexGenf")
|
||||
.add("glGetTexGend")
|
||||
.add("glTexImage1D")
|
||||
.add("glTexImage2D")
|
||||
.add("glTexImage3D")
|
||||
@@ -229,8 +236,10 @@ public final class AngelicaRedirector {
|
||||
.add("glTranslatef")
|
||||
.add("glVertex2d")
|
||||
.add("glVertex2f")
|
||||
.add("glVertex2i")
|
||||
.add("glVertex3d")
|
||||
.add("glVertex3f")
|
||||
.add("glVertex3i")
|
||||
.add("glVertexPointer")
|
||||
.add("glColorPointer")
|
||||
.add("glNormalPointer")
|
||||
|
||||
@@ -40,6 +40,7 @@ public enum Mixins implements IMixins {
|
||||
, "angelica.glsm.MixinSplashProgressCaching"
|
||||
, "angelica.gui.MixinGuiOptions"
|
||||
, "angelica.optimizations.MixinRendererLivingEntity"
|
||||
, "angelica.rendering.MixinRenderGlobal_SelectionBox"
|
||||
)
|
||||
),
|
||||
|
||||
@@ -229,7 +230,6 @@ public enum Mixins implements IMixins {
|
||||
, "shaders.MixinRenderGlobal"
|
||||
, "shaders.MixinRenderHorse"
|
||||
, "shaders.MixinRenderItem"
|
||||
, "shaders.MixinRenderManager"
|
||||
, "shaders.MixinRenderNameTag"
|
||||
, "shaders.MixinRenderPlayerArmor"
|
||||
, "shaders.MixinTileEntityBeaconRenderer"
|
||||
@@ -238,6 +238,24 @@ public enum Mixins implements IMixins {
|
||||
)
|
||||
),
|
||||
|
||||
IRIS_SHADERS_RENDER_MANAGER(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addExcludedMod(TargetedMod.DRAGON_API)
|
||||
.addClientMixins(
|
||||
"shaders.MixinRenderManager"
|
||||
)
|
||||
),
|
||||
|
||||
IRIS_SHADERS_RENDER_MANAGER_DAPI(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addRequiredMod(TargetedMod.DRAGON_API)
|
||||
.addClientMixins(
|
||||
"shaders.MixinRenderManagerDAPI"
|
||||
)
|
||||
),
|
||||
|
||||
IRIS_RENDERING_NOBACKHAND(new MixinBuilder("Iris Hand Shaders")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.debug.OpenGLDebugging;
|
||||
import com.gtnewhorizons.angelica.hudcaching.HUDCaching;
|
||||
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.IGameSettingsExt;
|
||||
import com.gtnewhorizons.angelica.render.CloudRenderer;
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.gtnewhorizons.angelica.render;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.uniform.GlUniformFloat2v;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.GlProgram;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.GlShader;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.ShaderConstants;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.ShaderType;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat3v;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat4v;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformMatrix4f;
|
||||
import org.embeddedt.embeddium.impl.render.shader.ShaderLoader;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
public final class SelectionBoxRenderer {
|
||||
|
||||
private static GlProgram<SelectionBoxUniforms> program;
|
||||
private static int emptyVao;
|
||||
private static final Matrix4f mvpMatrix = new Matrix4f();
|
||||
private static final float[] colorBuf = new float[4];
|
||||
|
||||
private SelectionBoxRenderer() {}
|
||||
|
||||
public static void init() {
|
||||
final boolean needsGS = GLStateManager.wideLineEmulationEnabled;
|
||||
|
||||
final GlShader vs = ShaderLoader.loadShader(ShaderType.VERTEX, "angelica:selection_box.vert.glsl", ShaderConstants.EMPTY);
|
||||
final GlShader fs = ShaderLoader.loadShader(ShaderType.FRAGMENT, "angelica:selection_box.frag.glsl", ShaderConstants.EMPTY);
|
||||
final GlProgram.Builder builder = GlProgram.builder("SelectionBox").attachShader(vs).attachShader(fs);
|
||||
|
||||
GlShader gs = null;
|
||||
if (needsGS) {
|
||||
gs = ShaderLoader.loadShader(ShaderType.GEOM, "angelica:selection_box.geom.glsl", ShaderConstants.EMPTY);
|
||||
builder.attachShader(gs);
|
||||
}
|
||||
|
||||
program = builder.link(ctx -> new SelectionBoxUniforms(
|
||||
ctx.bindUniform("u_MVP", GlUniformMatrix4f::new),
|
||||
ctx.bindUniform("u_Min", GlUniformFloat3v::new),
|
||||
ctx.bindUniform("u_Max", GlUniformFloat3v::new),
|
||||
ctx.bindUniform("u_Color", GlUniformFloat4v::new),
|
||||
needsGS ? ctx.bindUniform("u_ViewportSize", GlUniformFloat2v::new) : null,
|
||||
needsGS ? ctx.bindUniform("u_LineWidth", GlUniformFloat::new) : null));
|
||||
|
||||
vs.destroy();
|
||||
fs.destroy();
|
||||
if (gs != null) gs.destroy();
|
||||
|
||||
emptyVao = GL30.glGenVertexArrays();
|
||||
}
|
||||
|
||||
public static void draw(AxisAlignedBB aabb, int color) {
|
||||
if (program == null) return;
|
||||
|
||||
final SelectionBoxUniforms uniforms = program.getInterface();
|
||||
|
||||
program.bind();
|
||||
|
||||
GLStateManager.getProjectionMatrix().mul(GLStateManager.getModelViewMatrix(), mvpMatrix);
|
||||
uniforms.mvp.set(mvpMatrix);
|
||||
uniforms.min.set((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ);
|
||||
uniforms.max.set((float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ);
|
||||
|
||||
if (color != -1) {
|
||||
colorBuf[0] = ((color >> 16) & 0xFF) / 255.0f;
|
||||
colorBuf[1] = ((color >> 8) & 0xFF) / 255.0f;
|
||||
colorBuf[2] = (color & 0xFF) / 255.0f;
|
||||
colorBuf[3] = 1.0f;
|
||||
} else {
|
||||
final Color4 c = GLStateManager.getColor();
|
||||
colorBuf[0] = c.getRed();
|
||||
colorBuf[1] = c.getGreen();
|
||||
colorBuf[2] = c.getBlue();
|
||||
colorBuf[3] = c.getAlpha();
|
||||
}
|
||||
uniforms.color.set(colorBuf);
|
||||
|
||||
if (uniforms.viewportSize != null) {
|
||||
uniforms.viewportSize.set(GLStateManager.getViewportState().width, GLStateManager.getViewportState().height);
|
||||
uniforms.lineWidth.setFloat(GLStateManager.getLineState().getWidth());
|
||||
}
|
||||
|
||||
GLStateManager.glBindVertexArray(emptyVao);
|
||||
GL11.glDrawArrays(GL11.GL_LINES, 0, 24);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
|
||||
program.unbind();
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
if (program != null) {
|
||||
program.destroy();
|
||||
program = null;
|
||||
}
|
||||
if (emptyVao != 0) {
|
||||
GL30.glDeleteVertexArrays(emptyVao);
|
||||
emptyVao = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private record SelectionBoxUniforms(GlUniformMatrix4f mvp, GlUniformFloat3v min, GlUniformFloat3v max, GlUniformFloat4v color, GlUniformFloat2v viewportSize, GlUniformFloat lineWidth) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package me.jellysquid.mods.sodium.client.gui;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader;
|
||||
import jss.notfine.core.Settings;
|
||||
import jss.notfine.core.SettingsManager;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.ReeseSodiumVideoOptionsScreen;
|
||||
@@ -272,14 +273,16 @@ public class SodiumGameOptionPages {
|
||||
.setImpact(OptionImpact.VARIES)
|
||||
.setEnabled(GLStateManager.capabilities != null)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_map_buffer_range.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_map_buffer_range.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.advanced.useMapBufferRange = value, opts -> opts.advanced.useMapBufferRange)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.setImpact(OptionImpact.VARIES)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(StreamingUploader.UploadStrategy.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.upload_method.name"))
|
||||
.setTooltip(I18n.format("sodium.options.upload_method.tooltip"))
|
||||
.setControl(o ->
|
||||
new CyclingControl<>(o, StreamingUploader.UploadStrategy.class, StreamingUploader.UploadStrategy.values())
|
||||
)
|
||||
.setBinding((opts, value) -> opts.advanced.streamingUploadStrategy = value, opts -> opts.advanced.streamingUploadStrategy)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.setImpact(OptionImpact.VARIES)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.enable_deferred_batching.name"))
|
||||
.setTooltip(I18n.format("sodium.options.enable_deferred_batching.tooltip"))
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.MultiDrawMode;
|
||||
import net.coderbot.iris.Iris;
|
||||
@@ -33,7 +34,7 @@ public class SodiumGameOptions {
|
||||
public boolean useParticleCulling = true;
|
||||
public boolean allowDirectMemoryAccess = true;
|
||||
public boolean ignoreDriverBlacklist = false;
|
||||
public boolean useMapBufferRange = false;
|
||||
public StreamingUploader.UploadStrategy streamingUploadStrategy = StreamingUploader.UploadStrategy.MAP_BUFFER_RANGE;
|
||||
public boolean enableDeferredBatching = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,10 @@ import net.coderbot.iris.gl.texture.PixelType;
|
||||
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
|
||||
import net.coderbot.iris.uniforms.SystemTimeUniforms;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.embeddedt.embeddium.impl.render.shader.ShaderLoader;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
public class CenterDepthSampler {
|
||||
@@ -45,16 +42,9 @@ public class CenterDepthSampler {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
|
||||
this.framebuffer.addColorAttachment(0, texture);
|
||||
ProgramBuilder builder;
|
||||
|
||||
try {
|
||||
String fsh = new String(IOUtils.toByteArray(Objects.requireNonNull(getClass().getResourceAsStream("/centerDepth.fsh"))), StandardCharsets.UTF_8);
|
||||
String vsh = new String(IOUtils.toByteArray(Objects.requireNonNull(getClass().getResourceAsStream("/centerDepth.vsh"))), StandardCharsets.UTF_8);
|
||||
|
||||
builder = ProgramBuilder.begin("centerDepthSmooth", vsh, null, fsh, ImmutableSet.of(0, 1, 2));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String vsh = ShaderLoader.getShaderSource("angelica:centerDepth.vsh");
|
||||
String fsh = ShaderLoader.getShaderSource("angelica:centerDepth.fsh");
|
||||
ProgramBuilder builder = ProgramBuilder.begin("centerDepthSmooth", vsh, null, fsh, ImmutableSet.of(0, 1, 2));
|
||||
|
||||
builder.addDynamicSampler(depthSupplier, "depth");
|
||||
builder.addDynamicSampler(() -> altTexture, "altDepth");
|
||||
|
||||
@@ -187,6 +187,7 @@ options.angelica.fontconfig.aamode.aa_none=Font AA: OFF
|
||||
options.angelica.fontconfig.aamode.aa_4x=Font AA: 4x MSAA
|
||||
options.angelica.fontconfig.aamode.aa_16x=Font AA: 16x MSAA
|
||||
options.angelica.fontconfig.custom_font_scale=Custom Font Scale: %s
|
||||
options.angelica.fontconfig.shadow_offset_unicode=Unicode Shadow Offset: %s
|
||||
options.angelica.fontconfig.font_quality.tooltip=The quality at which custom fonts are rendered, making them less pixelated at the expense of some performance and memory.
|
||||
options.angelica.fontconfig.shadow_offset.tooltip=The distance at which the fonts' shadows are drawn. Also affects the way §lbold§r text is drawn.
|
||||
options.angelica.fontconfig.shadow_copies.tooltip=The number of shadows to be drawn behind text, all offset so as to provide a fake 3D effect.
|
||||
@@ -198,6 +199,7 @@ options.angelica.fontconfig.glyph_spacing.tooltip=The spacing between each indiv
|
||||
options.angelica.fontconfig.font_aa_strength.tooltip=The spacing of samples used in font antialiasing. High values may cause fonts to look blurry, low values may cause aliasing. See what works best with your settings.
|
||||
options.angelica.fontconfig.aamode.tooltip=The font antialiasing mode. Can significantly improve the appearance and readability of text that's being scaled or viewed at oblique angles, at the expense of some performance.
|
||||
options.angelica.fontconfig.custom_font_scale.tooltip=A multiplier that affects the scale of custom fonts. Adjust this if text in your font of choice looks under-/over-sized relative to text that does not use custom fonts.
|
||||
options.angelica.fontconfig.shadow_offset_unicode.tooltip=A shadow offset multiplier applied only to the Unicode font. Set this to 1.0x if, for example, you use a texture pack that replaces portions of the Unicode font with MC lookalikes.
|
||||
options.angelica.hudCaching=HUD Caching
|
||||
options.angelica.hudCaching.tooltip=Caches the HUD to a framebuffer and reuses it across frames to reduce rendering overhead. Requires HUD Caching to be enabled at startup. [Experimental]
|
||||
options.angelica.droppedItemLimit=Dropped Item Render Limit
|
||||
@@ -227,7 +229,10 @@ sodium.options.multidraw_mode.tooltip=Controls how draw commands are dispatched
|
||||
sodium.options.multidraw_mode.direct=Direct
|
||||
sodium.options.multidraw_mode.indirect=Indirect
|
||||
sodium.options.multidraw_mode.individual=Individual
|
||||
sodium.options.use_map_buffer_range.name=Use MapBufferRange
|
||||
sodium.options.use_map_buffer_range.tooltip=Uses glMapBufferRange instead of glBufferSubData for streaming vertex uploads. May improve performance on some drivers.
|
||||
sodium.options.upload_method.name=Streaming Upload Method
|
||||
sodium.options.upload_method.tooltip=Changes the way the data gets streamed to the GPU. Some options may lead to better performance for some drivers.
|
||||
sodium.options.upload_method.buffer_data=BufferData
|
||||
sodium.options.upload_method.buffer_subdata=BufferSubData
|
||||
sodium.options.upload_method.map_buffer=MapBufferRange
|
||||
sodium.options.enable_deferred_batching.name=Deferred Particle Batching
|
||||
sodium.options.enable_deferred_batching.tooltip=Batches particle draw calls into fewer merged draws per layer. Disable if particles render incorrectly.
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,8 @@
|
||||
#version 330 core
|
||||
|
||||
uniform vec4 u_Color;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = u_Color;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#version 330 core
|
||||
|
||||
layout(lines) in;
|
||||
layout(triangle_strip, max_vertices = 4) out;
|
||||
|
||||
uniform vec2 u_ViewportSize;
|
||||
uniform float u_LineWidth;
|
||||
|
||||
void main() {
|
||||
vec4 c0 = gl_in[0].gl_Position;
|
||||
vec4 c1 = gl_in[1].gl_Position;
|
||||
|
||||
vec2 n0 = c0.xy / c0.w;
|
||||
vec2 n1 = c1.xy / c1.w;
|
||||
|
||||
vec2 dir = normalize((n1 - n0) * u_ViewportSize);
|
||||
vec2 offset = vec2(-dir.y, dir.x) * u_LineWidth / u_ViewportSize;
|
||||
|
||||
gl_Position = vec4((n0 + offset) * c0.w, c0.z, c0.w);
|
||||
EmitVertex();
|
||||
gl_Position = vec4((n0 - offset) * c0.w, c0.z, c0.w);
|
||||
EmitVertex();
|
||||
gl_Position = vec4((n1 + offset) * c1.w, c1.z, c1.w);
|
||||
EmitVertex();
|
||||
gl_Position = vec4((n1 - offset) * c1.w, c1.z, c1.w);
|
||||
EmitVertex();
|
||||
EndPrimitive();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#version 330 core
|
||||
|
||||
uniform mat4 u_MVP;
|
||||
uniform vec3 u_Min;
|
||||
uniform vec3 u_Max;
|
||||
|
||||
const vec3 edges[24] = vec3[24](
|
||||
vec3(0,0,0), vec3(1,0,0), vec3(1,0,0), vec3(1,0,1),
|
||||
vec3(1,0,1), vec3(0,0,1), vec3(0,0,1), vec3(0,0,0),
|
||||
vec3(0,1,0), vec3(1,1,0), vec3(1,1,0), vec3(1,1,1),
|
||||
vec3(1,1,1), vec3(0,1,1), vec3(0,1,1), vec3(0,1,0),
|
||||
vec3(0,0,0), vec3(0,1,0), vec3(1,0,0), vec3(1,1,0),
|
||||
vec3(1,0,1), vec3(1,1,1), vec3(0,0,1), vec3(0,1,1)
|
||||
);
|
||||
|
||||
void main() {
|
||||
vec3 pos = mix(u_Min, u_Max, edges[gl_VertexID]);
|
||||
gl_Position = u_MVP * vec4(pos, 1.0);
|
||||
}
|
||||
@@ -7,5 +7,8 @@
|
||||
"injectors":{
|
||||
"maxShiftBy": 2
|
||||
},
|
||||
"compatibilityLevel": "JAVA_17"
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"overwrites": {
|
||||
"conformVisibility": true
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@
|
||||
"injectors":{
|
||||
"maxShiftBy": 2
|
||||
},
|
||||
"compatibilityLevel": "JAVA_21"
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"overwrites": {
|
||||
"conformVisibility": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
"injectors":{
|
||||
"maxShiftBy": 2
|
||||
},
|
||||
"compatibilityLevel": "JAVA_8"
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"overwrites": {
|
||||
"conformVisibility": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
"minVersion": "0.8.3-GTNH",
|
||||
"refmap": "mixins.angelica.refmap.json",
|
||||
"target": "@env(DEFAULT)",
|
||||
"compatibilityLevel": "JAVA_8"
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"overwrites": {
|
||||
"conformVisibility": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,8 @@
|
||||
"package": "com.gtnewhorizons.angelica.mixins.late",
|
||||
"refmap": "mixins.angelica.refmap.json",
|
||||
"target": "@env(DEFAULT)",
|
||||
"compatibilityLevel": "JAVA_17"
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"overwrites": {
|
||||
"conformVisibility": true
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,9 @@
|
||||
"package": "com.gtnewhorizons.angelica.mixins.late",
|
||||
"refmap": "mixins.angelica.refmap.json",
|
||||
"target": "@env(DEFAULT)",
|
||||
"compatibilityLevel": "JAVA_21"
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"overwrites": {
|
||||
"conformVisibility": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
"package": "com.gtnewhorizons.angelica.mixins.late",
|
||||
"refmap": "mixins.angelica.refmap.json",
|
||||
"target": "@env(DEFAULT)",
|
||||
"compatibilityLevel": "JAVA_8"
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"overwrites": {
|
||||
"conformVisibility": true
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.render.PanoramaRenderer;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -12,14 +13,14 @@ import org.spongepowered.asm.mixin.Shadow;
|
||||
public abstract class MixinGuiMainMenu extends GuiScreen {
|
||||
|
||||
@Shadow private int panoramaTimer;
|
||||
@Shadow private static ResourceLocation[] titlePanoramaPaths;
|
||||
@Final @Shadow private static ResourceLocation[] titlePanoramaPaths;
|
||||
|
||||
/**
|
||||
* @author Angelica
|
||||
* @reason Replace panorama with modern equivalent
|
||||
*/
|
||||
@Overwrite
|
||||
private void renderSkybox(int mouseX, int mouseY, float partialTicks) {
|
||||
public void renderSkybox(int mouseX, int mouseY, float partialTicks) {
|
||||
PanoramaRenderer.getInstance().renderSkybox(this.panoramaTimer, partialTicks, titlePanoramaPaths, this.mc, this.width, this.height, this.zLevel);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.rendering;
|
||||
|
||||
import com.gtnewhorizons.angelica.render.SelectionBoxRenderer;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
||||
@Mixin(RenderGlobal.class)
|
||||
public class MixinRenderGlobal_SelectionBox {
|
||||
|
||||
/**
|
||||
* @author Angelica
|
||||
* @reason Optimize selection box rendering
|
||||
*/
|
||||
@Overwrite
|
||||
public static void drawOutlinedBoundingBox(AxisAlignedBB aabb, int color) {
|
||||
SelectionBoxRenderer.draw(aabb, color);
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.EntityIdHelper;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Dynamic;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(RenderManager.class)
|
||||
public class MixinRenderManagerDAPI {
|
||||
|
||||
@Dynamic
|
||||
@WrapOperation(
|
||||
method = "func_147939_a(Lnet/minecraft/entity/Entity;DDDFFZ)Z",
|
||||
at = @At(remap = false, value = "INVOKE", target = "LReika/DragonAPI/Instantiable/Event/Client/EntityRenderEvent;fire(Lnet/minecraft/client/renderer/entity/Render;Lnet/minecraft/entity/Entity;DDDFF)V"),
|
||||
require = 1 // Require this if DAPI is present, which should be the case when this mixin is applied.
|
||||
)
|
||||
private void iris$wrapDoRenderDragonAPI(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
int entityId = EntityIdHelper.getEntityId(entity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityId);
|
||||
ItemIdManager.resetItemId();
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
}
|
||||
}
|
||||
@@ -529,6 +529,41 @@ class CompatShaderTransformerTest {
|
||||
assertTrue(result.contains("angelica_SceneColor"), "should reference angelica_SceneColor");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testVersionPatternDoesNotEatNextLine() {
|
||||
String src = "#version 330\nsomeword\n";
|
||||
|
||||
String result = CompatShaderTransformer.transform(src, false);
|
||||
assertTrue(result.contains("someword"), "Next-line word must not be eaten by version fixup");
|
||||
assertTrue(result.contains("#version 330 core"), "Version should be upgraded to core");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testModernShaderWithoutCoreKeyword() {
|
||||
String src = """
|
||||
#version 430
|
||||
in vec3 Position;
|
||||
uniform mat4 ModelViewMat;
|
||||
uniform mat4 ProjMat;
|
||||
out vec4 vertexColor;
|
||||
out float fogDistance;
|
||||
void main() {
|
||||
vec4 finalPos = vec4(Position, 1.0);
|
||||
vec4 modelPos = ModelViewMat * finalPos;
|
||||
gl_Position = ProjMat * modelPos;
|
||||
fogDistance = length(modelPos.xz);
|
||||
vertexColor = vec4(1.0);
|
||||
}
|
||||
""";
|
||||
|
||||
String result = CompatShaderTransformer.transform(src, false);
|
||||
assertTrue(result.contains("#version 430 core"), "Version should get 'core' profile added");
|
||||
assertTrue(result.contains("in vec3 Position"), "'in' keyword must not be eaten");
|
||||
assertTrue(result.contains("ModelViewMat"), "Shader content must be preserved");
|
||||
assertTrue(result.contains("ProjMat"), "Shader content must be preserved");
|
||||
assertTrue(result.contains("fogDistance"), "Shader content must be preserved");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLegacyQualifierConversion() {
|
||||
String vertSrc = """
|
||||
|
||||
@@ -2,11 +2,11 @@ package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
|
||||
import com.gtnewhorizons.angelica.AngelicaExtension;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.OrphanStreamingBuffer.UploadStrategy;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader.UploadStrategy;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
@@ -20,25 +20,10 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
@ExtendWith(AngelicaExtension.class)
|
||||
class StreamingBufferTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(UploadStrategy.class)
|
||||
void orphan_firstUploadReturnsZero(UploadStrategy strategy) {
|
||||
OrphanStreamingBuffer buf = new OrphanStreamingBuffer(strategy);
|
||||
try {
|
||||
ByteBuffer data = memAlloc(128);
|
||||
fillPattern(data);
|
||||
data.flip();
|
||||
assertEquals(0, buf.upload(data, 32), "First upload should return offset 0");
|
||||
memFree(data);
|
||||
} finally {
|
||||
buf.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(UploadStrategy.class)
|
||||
void orphan_dataIntegrity(UploadStrategy strategy) {
|
||||
OrphanStreamingBuffer buf = new OrphanStreamingBuffer(strategy);
|
||||
OrphanStreamingBuffer buf = new OrphanStreamingBuffer();
|
||||
try {
|
||||
ByteBuffer data = memAlloc(64);
|
||||
ByteBuffer readBack = null;
|
||||
@@ -46,7 +31,7 @@ class StreamingBufferTest {
|
||||
for (int i = 0; i < 64; i++) data.put((byte) i);
|
||||
data.flip();
|
||||
|
||||
buf.upload(data, 16);
|
||||
buf.upload(strategy, data);
|
||||
|
||||
// Read back via glGetBufferSubData
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buf.getBufferId());
|
||||
@@ -66,171 +51,6 @@ class StreamingBufferTest {
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(UploadStrategy.class)
|
||||
void orphan_multipleUploadsSubAllocate(UploadStrategy strategy) {
|
||||
OrphanStreamingBuffer buf = new OrphanStreamingBuffer(strategy);
|
||||
try {
|
||||
final int stride = 16;
|
||||
ByteBuffer small = memAlloc(64);
|
||||
ByteBuffer big = memAlloc(256);
|
||||
ByteBuffer readBack = null;
|
||||
try {
|
||||
// First upload: small
|
||||
fillPattern(small);
|
||||
small.flip();
|
||||
int v1 = buf.upload(small, stride);
|
||||
assertEquals(0, v1, "First upload should be at offset 0");
|
||||
|
||||
// Second upload: larger — sub-allocates after first (64KB min capacity)
|
||||
fillPattern(big);
|
||||
big.flip();
|
||||
int v2 = buf.upload(big, stride);
|
||||
assertTrue(v2 > 0, "Second upload should sub-allocate at non-zero offset");
|
||||
|
||||
// Verify second upload's data at its offset
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buf.getBufferId());
|
||||
readBack = memAlloc(buf.getCapacity());
|
||||
GL15.glGetBufferSubData(GL15.GL_ARRAY_BUFFER, 0, readBack);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
int byteOffset = v2 * stride;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
assertEquals((byte) (i & 0xFF), readBack.get(byteOffset + i), "Mismatch at byte " + i);
|
||||
}
|
||||
} finally {
|
||||
memFree(small);
|
||||
memFree(big);
|
||||
if (readBack != null) memFree(readBack);
|
||||
}
|
||||
} finally {
|
||||
buf.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(UploadStrategy.class)
|
||||
void orphan_subAllocationReturnsIncreasingOffsets(UploadStrategy strategy) {
|
||||
OrphanStreamingBuffer buf = new OrphanStreamingBuffer(strategy);
|
||||
try {
|
||||
final int stride = 16;
|
||||
final int dataSize = 64; // 4 vertices worth
|
||||
|
||||
ByteBuffer data1 = memAlloc(dataSize);
|
||||
ByteBuffer data2 = memAlloc(dataSize);
|
||||
ByteBuffer data3 = memAlloc(dataSize);
|
||||
ByteBuffer readBack = null;
|
||||
try {
|
||||
// First upload: offset 0
|
||||
for (int i = 0; i < dataSize; i++) data1.put((byte) (i + 10));
|
||||
data1.flip();
|
||||
int v1 = buf.upload(data1, stride);
|
||||
assertEquals(0, v1, "First upload should be at vertex 0");
|
||||
|
||||
// Second upload: should be at aligned offset after first
|
||||
for (int i = 0; i < dataSize; i++) data2.put((byte) (i + 20));
|
||||
data2.flip();
|
||||
int v2 = buf.upload(data2, stride);
|
||||
assertTrue(v2 > 0, "Second upload should be at a non-zero vertex offset");
|
||||
assertEquals(0, v2 % 4, "Vertex offset must be quad-aligned (multiple of 4)");
|
||||
|
||||
// Third upload
|
||||
for (int i = 0; i < dataSize; i++) data3.put((byte) (i + 30));
|
||||
data3.flip();
|
||||
int v3 = buf.upload(data3, stride);
|
||||
assertTrue(v3 > v2, "Third upload should be after second");
|
||||
assertEquals(0, v3 % 4, "Vertex offset must be quad-aligned");
|
||||
|
||||
// Verify all three regions have correct data
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buf.getBufferId());
|
||||
readBack = memAlloc(buf.getCapacity());
|
||||
GL15.glGetBufferSubData(GL15.GL_ARRAY_BUFFER, 0, readBack);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
for (int i = 0; i < dataSize; i++) {
|
||||
assertEquals((byte) (i + 10), readBack.get(v1 * stride + i), "Upload 1 mismatch at byte " + i);
|
||||
assertEquals((byte) (i + 20), readBack.get(v2 * stride + i), "Upload 2 mismatch at byte " + i);
|
||||
assertEquals((byte) (i + 30), readBack.get(v3 * stride + i), "Upload 3 mismatch at byte " + i);
|
||||
}
|
||||
} finally {
|
||||
memFree(data1);
|
||||
memFree(data2);
|
||||
memFree(data3);
|
||||
if (readBack != null) memFree(readBack);
|
||||
}
|
||||
} finally {
|
||||
buf.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(UploadStrategy.class)
|
||||
void orphan_overflowResetsToZero(UploadStrategy strategy) {
|
||||
OrphanStreamingBuffer buf = new OrphanStreamingBuffer(strategy);
|
||||
try {
|
||||
final int stride = 16;
|
||||
|
||||
// First upload: establishes capacity
|
||||
ByteBuffer data1 = memAlloc(64);
|
||||
try {
|
||||
fillPattern(data1);
|
||||
data1.flip();
|
||||
buf.upload(data1, stride);
|
||||
} finally {
|
||||
memFree(data1);
|
||||
}
|
||||
|
||||
int capacityAfterFirst = buf.getCapacity();
|
||||
|
||||
// Second upload: fills remaining space or overflows
|
||||
ByteBuffer data2 = memAlloc(capacityAfterFirst); // exactly fills or overflows
|
||||
try {
|
||||
fillPattern(data2);
|
||||
data2.flip();
|
||||
int v2 = buf.upload(data2, stride);
|
||||
// Either sub-allocated (if it fit after alignment) or reset to 0 (overflow)
|
||||
assertEquals(0, v2 % 4, "Offset must be quad-aligned");
|
||||
} finally {
|
||||
memFree(data2);
|
||||
}
|
||||
} finally {
|
||||
buf.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(UploadStrategy.class)
|
||||
void orphan_postDrawResetsForNextFrame(UploadStrategy strategy) {
|
||||
OrphanStreamingBuffer buf = new OrphanStreamingBuffer(strategy);
|
||||
try {
|
||||
final int stride = 16;
|
||||
|
||||
ByteBuffer data = memAlloc(64);
|
||||
try {
|
||||
// Frame 1: two uploads
|
||||
fillPattern(data);
|
||||
data.flip();
|
||||
buf.upload(data, stride);
|
||||
data.position(0).limit(64);
|
||||
int v2 = buf.upload(data, stride);
|
||||
assertTrue(v2 > 0, "Second upload in frame should be at non-zero offset");
|
||||
|
||||
// End of frame
|
||||
buf.postDraw();
|
||||
assertEquals(0, buf.getWritePos(), "writePos should reset after postDraw");
|
||||
|
||||
// Frame 2: first upload should be at offset 0 again (after orphan)
|
||||
data.position(0).limit(64);
|
||||
int v3 = buf.upload(data, stride);
|
||||
assertEquals(0, v3, "First upload after postDraw should return 0");
|
||||
} finally {
|
||||
memFree(data);
|
||||
}
|
||||
} finally {
|
||||
buf.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void persistent_uploadAlignment() {
|
||||
Assumptions.assumeTrue(RenderSystem.supportsBufferStorage(), "GL4.4+ required");
|
||||
|
||||
Reference in new issue
Block a user