Compare commits

...
12 Commits
47 changed files with 1438 additions and 849 deletions

No files matched your search

+1 -1
View File
@@ -61,7 +61,7 @@ dependencies {
// Iris Shaders
compileOnly('org.jetbrains:annotations:26.0.2')
api("com.github.GTNewHorizons:GTNHLib:0.6.40:dev")
api("com.github.GTNewHorizons:GTNHLib:0.7.7:dev")
shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-4.g6b42bca") {
exclude module: "antlr4" // we only want to shadow the runtime module
@@ -16,7 +16,7 @@ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
name = "Angelica",
version = Tags.VERSION,
dependencies = """
required-after:gtnhlib@[0.6.6,);\
required-after:gtnhlib@[0.7.7,);\
before:lwjgl3ify@[1.5.3,);\
after:hodgepodge@[2.4.4,);\
after:CodeChickenCore@[1.2.0,);\
@@ -13,6 +13,7 @@ import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.IOUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import java.io.IOException;
@@ -161,6 +162,15 @@ public class BatchingFontRenderer {
pushQuadIdx(vtxId);
}
private void pushTexRect(float x, float y, float w, float h, float itOff, int rgba, float uStart, float vStart, float uSz, float vSz) {
final int vtxId = vtxWriterIndex;
pushVtx(x + itOff, y, rgba, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(x - itOff, y + h, rgba, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(x + itOff + w, y, rgba, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(x - itOff + w, y + h, rgba, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushQuadIdx(vtxId);
}
private int pushQuadIdx(int startV) {
final int idx = idxWriterIndex;
batchIndices.put(idx, startV);
@@ -268,6 +278,8 @@ public class BatchingFontRenderer {
int fontAAModeLast = -1;
int fontAAStrengthLast = -1;
private void flushBatch() {
final int prevProgram = GLStateManager.glGetInteger(GL20.GL_CURRENT_PROGRAM);
// Sort&Draw
batchCommands.sort(FontDrawCmd.DRAW_ORDER_COMPARATOR);
@@ -282,10 +294,11 @@ public class BatchingFontRenderer {
GLStateManager.tryBlendFuncSeparate(blendSrcRGB, blendDstRGB, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glShadeModel(GL11.GL_FLAT);
if (FontConfig.fontAAMode != 0) {
final boolean canUseAA = FontConfig.fontAAMode != 0 && prevProgram == 0;
if (canUseAA) {
GL20.glVertexAttribPointer(texBoundAttrLocation, 4, false, 0, batchVtxTexBounds);
GL20.glEnableVertexAttribArray(texBoundAttrLocation);
lastActiveProgram = GLStateManager.getActiveProgram();
lastActiveProgram = prevProgram;
GLStateManager.glUseProgram(fontShaderId);
if (FontConfig.fontAAMode != fontAAModeLast) {
fontAAModeLast = FontConfig.fontAAMode;
@@ -296,6 +309,8 @@ public class BatchingFontRenderer {
GL20.glUniform1f(AAStrength, FontConfig.fontAAStrength / 120.f);
}
}
GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
GL11.glTexCoordPointer(2, 0, batchVtxTexCoords);
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 0, batchVtxColors);
@@ -304,6 +319,9 @@ public class BatchingFontRenderer {
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GLStateManager.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
GL11.glNormal3f(0.0f, 0.0f, 1.0f);
// Use plain for loop to avoid allocations
final FontDrawCmd[] cmdsData = batchCommands.elements();
final int cmdsSize = batchCommands.size();
@@ -326,7 +344,7 @@ public class BatchingFontRenderer {
GL11.glDrawElements(GL11.GL_TRIANGLES, batchIndices);
}
if (FontConfig.fontAAMode != 0) {
if (canUseAA) {
GLStateManager.glUseProgram(lastActiveProgram);
GL20.glDisableVertexAttribArray(texBoundAttrLocation);
}
@@ -509,49 +527,44 @@ public class BatchingFontRenderer {
final float vSz = fontProvider.getVSize(chr);
final float itOff = curItalic ? 1.0F : 0.0F; // italic offset
final float shadowOffset = fontProvider.getShadowOffset();
final int shadowCopies = FontConfig.shadowCopies;
final int boldCopies = FontConfig.boldCopies;
final ResourceLocation texture = fontProvider.getTexture(chr);
final int vtxId = vtxWriterIndex;
final int idxId = idxWriterIndex;
int vtxCount = 0;
if (enableShadow) {
pushVtx(curX + itOff + shadowOffset, heightNorth + shadowOffset, curShadowColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX - itOff + shadowOffset, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX + glyphW - 1.0F + itOff + shadowOffset, heightNorth + shadowOffset, curShadowColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushQuadIdx(vtxId + vtxCount);
vtxCount += 4;
for (int n = 1; n <= shadowCopies; n++) {
final float shadowOffsetPart = shadowOffset * ((float) n / shadowCopies);
pushTexRect(curX + shadowOffsetPart, heightNorth + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz);
if (curBold) {
final float shadowOffset2 = 2.0f * shadowOffset;
pushVtx(curX + itOff + shadowOffset2, heightNorth + shadowOffset, curShadowColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX - itOff + shadowOffset2, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX + glyphW - 1.0F + itOff + shadowOffset2, heightNorth + shadowOffset, curShadowColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset2, heightNorth + heightSouth + shadowOffset, curShadowColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushQuadIdx(vtxId + vtxCount);
vtxCount += 4;
if (curBold) {
pushTexRect(curX + 2.0f * shadowOffsetPart, heightNorth + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz);
}
}
}
pushVtx(curX + itOff, heightNorth, curColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX - itOff, heightNorth + heightSouth, curColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX + glyphW - 1.0F + itOff, heightNorth, curColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(curX + glyphW - 1.0F - itOff, heightNorth + heightSouth, curColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushQuadIdx(vtxId + vtxCount);
vtxCount += 4;
pushTexRect(curX, heightNorth, glyphW - 1.0f, heightSouth, itOff, curColor, uStart, vStart, uSz, vSz);
if (curBold) {
pushVtx(shadowOffset + curX + itOff, heightNorth, curColor, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(shadowOffset + curX - itOff, heightNorth + heightSouth, curColor, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(shadowOffset + curX + glyphW - 1.0F + itOff, heightNorth, curColor, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
pushVtx(shadowOffset + curX + glyphW - 1.0F - itOff, heightNorth + heightSouth, curColor, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
pushQuadIdx(vtxId + vtxCount);
vtxCount += 4;
for (int n = 1; n <= boldCopies; n++) {
final float shadowOffsetPart = shadowOffset * ((float) n / boldCopies);
pushTexRect(curX + shadowOffsetPart, heightNorth, glyphW - 1.0f, heightSouth, itOff, curColor, uStart, vStart, uSz, vSz);
}
}
/*
Vertex-per-char counts for different configurations
default: 4
shadow only: 4(1 + shadowCopies)
bold only: 4(1 + boldCopies)
both: 4(1 + 2 * shadowCopies + boldCopies)
*/
int charCount = 1;
if (enableShadow) { charCount += shadowCopies * (curBold ? 2 : 1); }
if (curBold) { charCount += boldCopies; }
final int vtxCount = 4 * charCount;
pushDrawCmd(idxId, vtxCount / 2 * 3, texture, chr > 255);
curX += (xAdvance + (curBold ? shadowOffset : 0.0f)) + getGlyphSpacing();
underlineEndX = curX;
strikethroughEndX = curX;
@@ -11,6 +11,7 @@ import net.minecraft.client.gui.GuiSlot;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.MathHelper;
import org.lwjgl.input.Keyboard;
import java.awt.Font;
@@ -26,6 +27,8 @@ public class FontConfigScreen extends GuiScreen {
private final GuiScreen parent;
private final String title;
private final String searchPrompt;
private final String testAreaPrompt;
private List<String> testAreaInfo;
private String currentPrimaryFontName;
private String currentFallbackFontName;
private FontList fontList;
@@ -33,10 +36,31 @@ public class FontConfigScreen extends GuiScreen {
private int selectedFallbackFontListPos = -1;
private ArrayList<Font> displayedFonts;
private GuiTextField searchBox;
private GuiTextField testArea;
private int sliderPages = 0;
private int displayedSliderPage = 0;
private final int sliderWidth = 160;
private final int sliderHeight = 20;
// need to save these separately
private IrisButton fwdButton;
private IrisButton backButton;
SliderClone.Option optFontQuality = new SliderClone.Option(6, 72, 6);
SliderClone.Option optShadowOffset = new SliderClone.Option(0, 2, 0.05f);
SliderClone.Option optShadowCopies = new SliderClone.Option(1, 8, 1);
SliderClone.Option optBoldCopies = new SliderClone.Option(1, 8, 1);
SliderClone.Option optGlyphAspect = new SliderClone.Option(-1, 1, 0.05f);
SliderClone.Option optGlyphScale = new SliderClone.Option(0.1f, 3, 0.05f);
SliderClone.Option optWhitespaceScale = new SliderClone.Option(0.1f, 3, 0.05f);
SliderClone.Option optGlyphSpacing = new SliderClone.Option(-2f, 2f, 0.05f);
SliderClone.Option optFontAAMode = new SliderClone.Option(0, 2, 1);
SliderClone.Option optFontAAStrength = new SliderClone.Option(1, 24, 1);
public FontConfigScreen(GuiScreen parent) {
this.title = I18n.format("options.angelica.fontconfig.title");
this.searchPrompt = I18n.format("options.angelica.fontconfig.searchprompt");
this.testAreaPrompt = I18n.format("options.angelica.fontconfig.testareaprompt");
this.parent = parent;
this.currentPrimaryFontName = FontConfig.customFontNamePrimary;
this.currentFallbackFontName = FontConfig.customFontNameFallback;
@@ -51,65 +75,175 @@ public class FontConfigScreen extends GuiScreen {
}
}
SliderClone.Option optFontQuality = new SliderClone.Option(6, 72, 6);
SliderClone.Option optShadowOffset = new SliderClone.Option(0, 2, 0.05f);
SliderClone.Option optGlyphAspect = new SliderClone.Option(-1, 1, 0.05f);
SliderClone.Option optGlyphScale = new SliderClone.Option(0.1f, 3, 0.05f);
SliderClone.Option optWhitespaceScale = new SliderClone.Option(0.1f, 3, 0.05f);
SliderClone.Option optGlyphSpacing = new SliderClone.Option(-2f, 2f, 0.05f);
SliderClone.Option optFontAAMode = new SliderClone.Option(0, 2, 1);
SliderClone.Option optFontAAStrength = new SliderClone.Option(1, 24, 1);
public void initGui() {
Keyboard.enableRepeatEvents(true);
searchBox = new GuiTextField(this.fontRendererObj, this.width / 2 - 120, 24, 240, 20);
searchBox.setMaxStringLength(64);
fontList = new FontList();
testArea = new GuiTextField(this.fontRendererObj, this.width * 5 / 6 - this.width / 7, 63 - 10, this.width * 2 / 7, 20);
testArea.setMaxStringLength(512);
testArea.setText(I18n.format("options.angelica.fontconfig.testareaexample"));
initButtons();
}
private void initButtons() {
this.buttonList.add(new IrisButton(this.width / 2 - 81 - 165, this.height - 20 - 7, 162, 20,
final int halfWidth = this.width / 2;
final int sliderSpacing = 4;
final int x1 = halfWidth - sliderWidth - sliderSpacing;
final int x2 = halfWidth;
final int x3 = halfWidth + sliderWidth + sliderSpacing;
final int y3 = this.height - 65 + 2 * (sliderHeight + sliderSpacing);
this.buttonList.add(new IrisButton(x1 - sliderWidth / 2, y3 - sliderHeight / 2, sliderWidth, sliderHeight,
FontConfig.enableCustomFont ? I18n.format("options.angelica.fontconfig.disable_custom_font") :
I18n.format("options.angelica.fontconfig.enable_custom_font"), this::toggleCustomFont));
this.buttonList.add(new IrisButton(this.width / 2 - 80, this.height - 20 - 7, 160, 20,
this.buttonList.add(new IrisButton(x2 - sliderWidth / 2, y3 - sliderHeight / 2, sliderWidth, sliderHeight,
I18n.format("options.angelica.fontconfig.reset_values"), this::resetValues));
this.buttonList.add(new IrisButton(this.width / 2 - 81 + 165, this.height - 20 - 7, 162, 20,
this.buttonList.add(new IrisButton(x3 - sliderWidth / 2, y3 - sliderHeight / 2, sliderWidth, sliderHeight,
I18n.format("gui.done"), button -> this.onClose()));
// might refactor later, feeling too lazy at the moment
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 186, this.height - 40 - 11, 120, 20,
optFontQuality, FontConfig.customFontQuality, this::setFontQuality,
value -> I18n.format("options.angelica.fontconfig.font_quality", String.format("%2.0f", value)),
"options.angelica.fontconfig.font_quality.tooltip"));
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 186, this.height - 60 - 15, 120, 20,
optShadowOffset, FontConfig.fontShadowOffset, value -> FontConfig.fontShadowOffset = value,
value -> I18n.format("options.angelica.fontconfig.shadow_offset", String.format("x%3.2f", value)),
"options.angelica.fontconfig.shadow_offset.tooltip"));
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 62, this.height - 40 - 11, 120, 20,
optGlyphAspect, FontConfig.glyphAspect, value -> FontConfig.glyphAspect = value,
value -> I18n.format("options.angelica.fontconfig.glyph_aspect", String.format("%3.2f", value)),
"options.angelica.fontconfig.glyph_aspect.tooltip"));
this.buttonList.add(new SliderClone( this.width / 2 - 60 - 62, this.height - 60 - 15, 120, 20,
optGlyphScale, FontConfig.glyphScale, value -> FontConfig.glyphScale = value,
value -> I18n.format("options.angelica.fontconfig.glyph_scale", String.format("x%3.2f", value)),
"options.angelica.fontconfig.glyph_scale.tooltip"));
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 62, this.height - 40 - 11, 120, 20,
optWhitespaceScale, FontConfig.whitespaceScale, value -> FontConfig.whitespaceScale = value,
value -> I18n.format("options.angelica.fontconfig.whitespace_scale", String.format("x%3.2f", value)),
"options.angelica.fontconfig.whitespace_scale.tooltip"));
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 62, this.height - 60 - 15, 120, 20,
optGlyphSpacing, FontConfig.glyphSpacing, value -> FontConfig.glyphSpacing = value,
value -> I18n.format("options.angelica.fontconfig.glyph_spacing", String.format("%3.2f", value)),
"options.angelica.fontconfig.glyph_spacing.tooltip"));
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 186, this.height - 40 - 11, 120, 20,
optFontAAStrength, FontConfig.fontAAStrength, value -> FontConfig.fontAAStrength = value.intValue(),
value -> I18n.format("options.angelica.fontconfig.font_aa_strength", String.format("%.0f", value)),
"options.angelica.fontconfig.font_aa_strength.tooltip"));
this.buttonList.add(new SliderClone( this.width / 2 - 60 + 186, this.height - 60 - 15, 120, 20,
optFontAAMode, FontConfig.fontAAMode, value -> FontConfig.fontAAMode = value.intValue(),
this::fontAAModeFormat,
"options.angelica.fontconfig.aamode.tooltip"));
backButton = new IrisButton(halfWidth - 20 - 224, this.height - 89 - 10, 40, 20,
"<", button -> this.switchPage(-1));
fwdButton = new IrisButton(halfWidth - 20 + 224, this.height - 89 - 10, 40, 20,
">", button -> this.switchPage(1));
this.buttonList.add(fwdButton);
this.buttonList.add(backButton);
initSliders();
}
private void initSliders() {
ArrayList<SliderClone> sliders = new ArrayList<>();
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optFontQuality)
.initialValue(FontConfig.customFontQuality)
.setter(this::setFontQuality)
.langKey("options.angelica.fontconfig.font_quality")
.formatString("%2.0f")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optShadowOffset)
.initialValue(FontConfig.fontShadowOffset)
.setter(value -> FontConfig.fontShadowOffset = value)
.langKey("options.angelica.fontconfig.shadow_offset")
.formatString("x%3.2f")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optGlyphAspect)
.initialValue(FontConfig.glyphAspect)
.setter(value -> FontConfig.glyphAspect = value)
.langKey("options.angelica.fontconfig.glyph_aspect")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optGlyphScale)
.initialValue(FontConfig.glyphScale)
.setter(value -> FontConfig.glyphScale = value)
.langKey("options.angelica.fontconfig.glyph_scale")
.formatString("x%3.2f")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optFontAAStrength)
.initialValue(FontConfig.fontAAStrength)
.setter(value -> FontConfig.fontAAStrength = value.intValue())
.langKey("options.angelica.fontconfig.font_aa_strength")
.formatString("%.0f")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optFontAAMode)
.initialValue(FontConfig.fontAAMode)
.setter(value -> FontConfig.fontAAMode = value.intValue())
.formatter(this::fontAAModeFormat)
.langKey("options.angelica.fontconfig.aamode")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optWhitespaceScale)
.initialValue(FontConfig.whitespaceScale)
.setter(value -> FontConfig.whitespaceScale = value)
.langKey("options.angelica.fontconfig.whitespace_scale")
.formatString("x%3.2f")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optGlyphSpacing)
.initialValue(FontConfig.glyphSpacing)
.setter(value -> FontConfig.glyphSpacing = value)
.langKey("options.angelica.fontconfig.glyph_spacing")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optShadowCopies)
.initialValue(FontConfig.shadowCopies)
.setter(value -> FontConfig.shadowCopies = value.intValue())
.langKey("options.angelica.fontconfig.shadow_copies")
.formatString("%.0f")
.build()
);
sliders.add(new SliderClone.SliderCloneBuilder()
.width(sliderWidth)
.height(sliderHeight)
.option(optBoldCopies)
.initialValue(FontConfig.boldCopies)
.setter(value -> FontConfig.boldCopies = value.intValue())
.langKey("options.angelica.fontconfig.bold_copies")
.formatString("%.0f")
.build()
);
final int halfWidth = this.width / 2;
final int sliderSpacing = 4;
final int x1 = halfWidth - sliderWidth - sliderSpacing;
final int x2 = halfWidth;
final int x3 = halfWidth + sliderWidth + sliderSpacing;
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.backButton.enabled = (this.displayedSliderPage != 0);
this.fwdButton.enabled = (this.displayedSliderPage != this.sliderPages);
final int start = 6 * this.displayedSliderPage;
final int end = Math.min(6 * (this.displayedSliderPage + 1), sliders.size());
List<SliderClone> s = sliders.subList(start, end);
try {
s.get(0).setCenterPosition(x1, y1);
s.get(1).setCenterPosition(x1, y2);
s.get(2).setCenterPosition(x2, y1);
s.get(3).setCenterPosition(x2, y2);
s.get(4).setCenterPosition(x3, y1);
s.get(5).setCenterPosition(x3, y2);
} catch (IndexOutOfBoundsException ignored) {
// we're on the last page and it has less than 6 sliders to display
}
this.buttonList.addAll(s);
}
private void onClose() {
@@ -141,6 +275,8 @@ public class FontConfigScreen extends GuiScreen {
} catch (ConfigException e) {
throw new RuntimeException(e);
}
currentPrimaryFontName = null;
currentFallbackFontName = null;
selectedPrimaryFontListPos = -1;
selectedFallbackFontListPos = -1;
FontStrategist.customFontInUse = false;
@@ -156,6 +292,12 @@ public class FontConfigScreen extends GuiScreen {
I18n.format("options.angelica.fontconfig.enable_custom_font");
}
private void switchPage(int offset) {
this.displayedSliderPage = MathHelper.clamp_int(this.displayedSliderPage + offset, 0, this.sliderPages);
this.buttonList.removeIf(guiButton -> guiButton instanceof SliderClone);
this.initSliders();
}
private int qualityLast = FontConfig.customFontQuality;
private void setFontQuality(float quality) {
@@ -179,7 +321,7 @@ public class FontConfigScreen extends GuiScreen {
private long lastStillTime = 0;
@Override
public void drawScreen(int mouseX, int mouseY, float delta) {
super.drawDefaultBackground();
drawBackground(0);
fontList.drawScreen(mouseX, mouseY, delta);
searchBox.drawTextBox();
// I bet you thought this was drawn inside the search box, not on top of it.
@@ -191,6 +333,34 @@ public class FontConfigScreen extends GuiScreen {
drawCenteredString(this.fontRendererObj, this.title, (int) (this.width * 0.5), 8, 0xFFFFFF);
drawCenteredString(this.fontRendererObj, I18n.format("options.angelica.fontconfig.currentfonts",
FontConfig.customFontNamePrimary, FontConfig.customFontNameFallback), (int) (this.width * 0.5), this.height - 92, 0xFFFFFF);
if (this.testAreaInfo == null) {
this.testAreaInfo = this.fontRendererObj.listFormattedStringToWidth(
I18n.format("options.angelica.fontconfig.testareainfo"), this.width / 4
);
}
int cumulativeY = 73;
for (String s : this.testAreaInfo) {
drawCenteredString(this.fontRendererObj, s, this.width * 5 / 6, cumulativeY, 0xFFFFFF);
cumulativeY += this.fontRendererObj.FONT_HEIGHT;
}
cumulativeY += 4;
this.testArea.yPosition = cumulativeY;
this.testArea.drawTextBox();
if (!this.testArea.isFocused() && this.testArea.getText().isEmpty()) {
this.drawCenteredString(this.fontRendererObj, this.testAreaPrompt,
this.testArea.xPosition + this.fontRendererObj.getStringWidth(this.testAreaPrompt) / 2 + 4,
this.testArea.yPosition + this.testArea.height / 2 - 4, 0xFFFFFF);
}
List<String> testText = this.fontRendererObj.listFormattedStringToWidth(
this.testArea.getText().replace('&', '§'), this.width / 4
);
cumulativeY += this.testArea.height + 4;
for (String s : testText) {
drawCenteredString(this.fontRendererObj, s, this.width * 5 / 6, cumulativeY, 0xFFFFFF);
cumulativeY += this.fontRendererObj.FONT_HEIGHT;
}
super.drawScreen(mouseX, mouseY, delta);
for (GuiButton guiButton : buttonList) {
@@ -235,10 +405,18 @@ public class FontConfigScreen extends GuiScreen {
if (this.searchBox.isFocused()) {
if (keyCode == Keyboard.KEY_ESCAPE) {
this.searchBox.setFocused(false);
return;
}
this.searchBox.textboxKeyTyped(typedChar, keyCode);
this.displayedFonts = filterFonts(this.searchBox.getText().toLowerCase());
}
if (this.testArea.isFocused()) {
if (keyCode == Keyboard.KEY_ESCAPE) {
this.testArea.setFocused(false);
return;
}
this.testArea.textboxKeyTyped(typedChar, keyCode);
}
if (keyCode == Keyboard.KEY_ESCAPE) {
this.onClose();
}
@@ -248,12 +426,14 @@ public class FontConfigScreen extends GuiScreen {
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
super.mouseClicked(mouseX, mouseY, mouseButton);
this.searchBox.mouseClicked(mouseX, mouseY, mouseButton);
this.testArea.mouseClicked(mouseX, mouseY, mouseButton);
this.fontList.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
public void updateScreen() {
this.searchBox.updateCursorCounter();
this.testArea.updateCursorCounter();
}
// this could be more efficient, but it's good enough as is
@@ -281,7 +461,7 @@ public class FontConfigScreen extends GuiScreen {
class FontList extends GuiSlot {
public FontList() {
super(FontConfigScreen.this.mc, FontConfigScreen.this.width, FontConfigScreen.this.height, 52, FontConfigScreen.this.height - 100, 18);
super(FontConfigScreen.this.mc, FontConfigScreen.this.width * 2 / 3, FontConfigScreen.this.height, 52, FontConfigScreen.this.height - 102, 18);
}
private void mouseClicked(int mouseX, int mouseY, int mouseButton) {
@@ -328,7 +508,7 @@ public class FontConfigScreen extends GuiScreen {
@Override
protected int getScrollBarX() {
return this.width * 11 / 12 - 5;
return this.width * 15 / 16 - 5;
}
@Override
@@ -340,7 +520,7 @@ public class FontConfigScreen extends GuiScreen {
protected void elementClicked(int index, boolean doubleClicked, int mouseX, int mouseY) {}
protected void drawBackground() {
drawDefaultBackground();
// do nothing, the font list doesn't occupy the entire screen
}
protected void drawSlot(int index, int x, int y, int p_148126_4_, Tessellator tessellator, int p_148126_6_, int p_148126_7_) {
@@ -1,8 +1,11 @@
package com.gtnewhorizons.angelica.client.gui;
import lombok.AllArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.resources.I18n;
import org.lwjgl.opengl.GL11;
import java.util.function.Consumer;
@@ -43,6 +46,53 @@ public class SliderClone extends GuiButton {
this.tooltipKey = tooltipKey;
}
public static SliderCloneBuilder builder() {
return new SliderCloneBuilder();
}
public void setCenterPosition(int x, int y) {
this.xPosition = x - this.width / 2;
this.yPosition = y - this.height / 2;
}
@Accessors(fluent = true) @Setter
public static class SliderCloneBuilder {
private int x = 0, y = 0; // center position, not a corner
private int width = 144, height = 20;
private Option option;
private float initialValue;
private Consumer<Float> setter;
private String formatString = "%3.2f";
private String langKey;
// overrides: if null, these get set to default values
private String tooltipKey;
private Function<Float, String> formatter;
public SliderClone build() {
if (this.formatter == null) {
this.formatter = value -> I18n.format(this.langKey, String.format(this.formatString, value));
}
if (this.tooltipKey == null) {
this.tooltipKey = this.langKey + ".tooltip";
}
return new SliderClone(
this.x - this.width / 2,
this.y - this.height / 2,
this.width,
this.height,
this.option,
this.initialValue,
this.setter,
this.formatter,
this.tooltipKey
);
}
}
/**
* Returns 0 if the button is disabled, 1 if the mouse is NOT hovering over this button and 2 if it IS hovering over
* this button.
@@ -0,0 +1,17 @@
package com.gtnewhorizons.angelica.compat.iris;
/**
* Interface implemented by BiomeGenBase via mixin to cache biome category.
* This avoids recomputing the category every frame for shader uniforms.
*/
public interface BiomeCategoryCache {
/**
* Gets the cached biome category ordinal, or -1 if not yet computed.
*/
int iris$getCachedCategory();
/**
* Sets the cached biome category ordinal.
*/
void iris$setCachedCategory(int category);
}
@@ -0,0 +1,102 @@
package com.gtnewhorizons.angelica.compat.iris;
import net.coderbot.iris.parsing.BiomeCategories;
import net.minecraft.world.biome.BiomeGenBase;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Detects and categorizes biomes from popular modded biome mods using cached class checks.
* Currently supports: BiomesOPlenty (BOP), Realistic World Gen (RWG)
*/
public class ModdedBiomeDetector {
private static boolean initialized = false;
// BiomesOPlenty (BOP) cache - dimension-specific base classes
// BOP 1.7.10 hierarchy: BOPBiome -> BOPEndBiome/BOPNetherBiome/BOPOverworldBiome -> specific biomes
private static Class<?> bopEndBiomeClass = null;
private static Class<?> bopNetherBiomeClass = null;
private static Class<?> bopOceanBiomeClass = null;
// Realistic World Gen (RWG) cache - base biome classes that extend BiomeGenBase
// LinkedHashMap maintains insertion order for deterministic behavior
private static final Map<Class<?>, BiomeCategories> rwgClassMap = new LinkedHashMap<>();
private static synchronized void initialize() {
if (initialized) return;
initialized = true;
initializeBOP();
initializeRWG();
}
private static void initializeBOP() {
try {
bopEndBiomeClass = Class.forName("biomesoplenty.common.biome.BOPEndBiome");
bopNetherBiomeClass = Class.forName("biomesoplenty.common.biome.BOPNetherBiome");
bopOceanBiomeClass = Class.forName("biomesoplenty.common.biome.BOPOceanBiome");
} catch (ClassNotFoundException ignored) {
// BOP not installed
}
}
private static void initializeRWG() {
// RWG adds actual BiomeGenBase subclasses in rwg.biomes.base package
tryAddRWGClass("rwg.biomes.base.BaseBiomeOcean", BiomeCategories.OCEAN);
tryAddRWGClass("rwg.biomes.base.BaseBiomeRiver", BiomeCategories.RIVER);
tryAddRWGClass("rwg.biomes.base.BaseBiomePlains", BiomeCategories.PLAINS);
tryAddRWGClass("rwg.biomes.base.BaseBiomeColdPlains", BiomeCategories.PLAINS);
tryAddRWGClass("rwg.biomes.base.BaseBiomeHotPlains", BiomeCategories.PLAINS);
tryAddRWGClass("rwg.biomes.base.BaseBiomeHotDesert", BiomeCategories.DESERT);
tryAddRWGClass("rwg.biomes.base.BaseBiomeSnowDesert", BiomeCategories.DESERT); // Cold desert, but still desert
tryAddRWGClass("rwg.biomes.base.BaseBiomeJungle", BiomeCategories.JUNGLE);
tryAddRWGClass("rwg.biomes.base.BaseBiomeTropicalIsland", BiomeCategories.JUNGLE); // Tropical islands are jungle-like
tryAddRWGClass("rwg.biomes.base.BaseBiomeRedwood", BiomeCategories.FOREST); // Redwood/Sequoia forests
tryAddRWGClass("rwg.biomes.base.BaseBiomeTemperateForest", BiomeCategories.FOREST);
tryAddRWGClass("rwg.biomes.base.BaseBiomeColdForest", BiomeCategories.TAIGA); // Cold forests are taiga-like
tryAddRWGClass("rwg.biomes.base.BaseBiomeHotForest", BiomeCategories.FOREST);
tryAddRWGClass("rwg.biomes.base.BaseBiomeSnowForest", BiomeCategories.TAIGA); // Snow forests are taiga
}
private static void tryAddRWGClass(String className, BiomeCategories category) {
try {
final Class<?> clazz = Class.forName(className);
rwgClassMap.put(clazz, category);
} catch (ClassNotFoundException ignored) {
// Class not available, RWG not installed or different version
}
}
/**
* Attempts to detect the biome category for modded biomes.
* Returns null if no modded biome detection applies.
*/
public static BiomeCategories detectModdedBiome(BiomeGenBase biome) {
if (!initialized) {
initialize();
}
// BiomesOPlenty detection - dimension-specific classes give us clear categories
if (bopEndBiomeClass != null && bopEndBiomeClass.isInstance(biome)) {
return BiomeCategories.THE_END;
}
if (bopNetherBiomeClass != null && bopNetherBiomeClass.isInstance(biome)) {
return BiomeCategories.NETHER;
}
if (bopOceanBiomeClass != null && bopOceanBiomeClass.isInstance(biome)) {
return BiomeCategories.OCEAN;
}
// For other BOP overworld biomes (e.g., Alps, Arctic, BambooForest),
// fall through to name/property-based detection
// Realistic World Gen detection
for (Map.Entry<Class<?>, BiomeCategories> entry : rwgClassMap.entrySet()) {
if (entry.getKey().isInstance(biome)) {
return entry.getValue();
}
}
return null;
}
}
@@ -9,35 +9,62 @@ import net.minecraft.util.MathHelper;
import org.joml.Matrix4f;
import org.joml.Vector3d;
import org.joml.Vector4f;
import org.joml.Vector3f;
/**
* Singleton camera instance that tracks the current camera position and orientation.
*/
@Getter
public class Camera {
final Vector3d pos = new Vector3d();
final BlockPos blockPos = new BlockPos();
float pitch;
float yaw;
EntityLivingBase entity;
boolean thirdPerson;
final float partialTicks;
public static final Camera INSTANCE = new Camera();
public Camera(EntityLivingBase entity, float partialTicks) {
private final Vector3d pos = new Vector3d();
private final BlockPos blockPos = new BlockPos();
private final Vector3f offset = new Vector3f();
private final Matrix4f inverseModelView = new Matrix4f();
private float pitch;
private float yaw;
private EntityLivingBase entity;
private boolean thirdPerson;
private float partialTicks;
private Camera() {
}
/**
* Updates the camera position and orientation based on the current entity and partial ticks.
*
* @param entity The entity to track (usually the render view entity)
* @param partialTicks The partial tick time for interpolation
*/
public void update(EntityLivingBase entity, float partialTicks) {
this.partialTicks = partialTicks;
final Vector4f offset = new Vector4f(); // third person offset
final Matrix4f inverseModelView = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()).invert();
inverseModelView.transform(offset);
final double camX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks + offset.x;
final double camY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks + offset.y;
final double camZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks + offset.z;
this.entity = entity;
// Entity position (interpolated, at feet level)
final double entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks;
final double entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks;
final double entityZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks;
final double eyeHeight = entity.getEyeHeight();
thirdPerson = Minecraft.getMinecraft().gameSettings.thirdPersonView > 0;
final double camX, camY, camZ;
offset.set(0, 0, 0);
if (thirdPerson) {
// Third person: use inverse modelview to find camera offset
inverseModelView.set(RenderingState.INSTANCE.getModelViewMatrix()).invert();
inverseModelView.transformPosition(offset);
}
camX = entityX + offset.x;
camY = entityY + eyeHeight + offset.y;
camZ = entityZ + offset.z;
pos.set(camX, camY, camZ);
blockPos.set(MathHelper.floor_double(camX), MathHelper.floor_double(camY), MathHelper.floor_double(camZ));
pitch = entity.cameraPitch;
yaw = entity.rotationYaw;
thirdPerson = Minecraft.getMinecraft().gameSettings.thirdPersonView == 1;
}
}
@@ -0,0 +1,17 @@
package com.gtnewhorizons.angelica.compat.mojang;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerControllerMP;
public final class GameModeUtil {
private GameModeUtil() {
}
public static boolean isSpectator() {
final PlayerControllerMP controller = Minecraft.getMinecraft().playerController;
if (controller == null) {
return false;
}
return controller.currentGameType.getID() == 3;
}
}
@@ -26,6 +26,16 @@ public class FontConfig {
@Config.RangeFloat(min = 0F, max = 2F)
public static float fontShadowOffset;
@Config.Comment("The number of shadows to be drawn behind text at various offsets.")
@Config.DefaultInt(1)
@Config.RangeInt(min = 1, max = 8)
public static int shadowCopies;
@Config.Comment("The number of bold copies to be drawn behind text at various offsets.")
@Config.DefaultInt(2)
@Config.RangeInt(min = 1, max = 8)
public static int boldCopies;
@Config.Comment("Influences the aspect ratio of each glyph.")
@Config.DefaultFloat(0F)
@Config.RangeFloat(min = -1F, max = 1F)
@@ -16,6 +16,7 @@ import com.gtnewhorizons.angelica.glsm.stacks.LightModelStateStack;
import com.gtnewhorizons.angelica.glsm.stacks.LightStateStack;
import com.gtnewhorizons.angelica.glsm.stacks.MaterialStateStack;
import com.gtnewhorizons.angelica.glsm.stacks.MatrixModeStack;
import com.gtnewhorizons.angelica.glsm.stacks.TextureBindingStack;
import com.gtnewhorizons.angelica.glsm.stacks.ViewPortStateStack;
import com.gtnewhorizons.angelica.glsm.states.Color4;
import com.gtnewhorizons.angelica.glsm.states.ISettableState;
@@ -66,7 +67,6 @@ import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.opengl.KHRDebug;
import java.lang.Math;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
@@ -1513,8 +1513,8 @@ public class GLStateManager {
GL11.glNewList(list, mode);
List<IStateStack<?>> stacks = Feature.maskToFeatures(GL11.GL_ALL_ATTRIB_BITS);
int size = stacks.size();
final int size = stacks.size();
//noinspection ForLoopReplaceableByForEach
for(int i = 0; i < size; i++) {
IStateStack<?> stack = stacks.get(i);
@@ -1525,6 +1525,12 @@ public class GLStateManager {
if(glListMode == GL11.GL_COMPILE) {
pushState(GL11.GL_ALL_ATTRIB_BITS);
}
// Band-aid fix to prevent color & texture leaks
color.setRed(-1);
color.setGreen(-1);
color.setBlue(-1);
textures.getTextureUnitBindings(getActiveTextureUnit()).setBinding(-1);
}
public static void glEndList() {
@@ -1540,12 +1546,33 @@ public class GLStateManager {
final Set<Map.Entry<IStateStack<?>, ISettableState<?>>> changedStates = new ObjectArraySet<>();
for(Map.Entry<IStateStack<?>, ISettableState<?>> entry : glListStates.entrySet()) {
// If the current stack state is different than the copy of the state at the start
if(!((ISettableState<?>)entry.getKey()).sameAs(entry.getValue())) {
if(!((ISettableState<?>)entry.getKey()).sameAs(entry.getValue())
&& !(entry.getKey() instanceof TextureBinding)
&& !(entry.getKey() instanceof Color4)) {
// Then we want to put into the change set the stack and the copy of the state now
changedStates.add(new AbstractMap.SimpleEntry<>(entry.getKey(), (ISettableState<?>) ((ISettableState<?>) entry.getKey()).copy()));
}
}
if(changedStates.size() != 0) {
final TextureBindingStack activeBinding = textures.getTextureUnitBindings(getActiveTextureUnit());
if (activeBinding.getBinding() != -1) {
changedStates.add(new AbstractMap.SimpleEntry<>(
activeBinding,
activeBinding.copy()
));
} else {
activeBinding.set(glListStates.get(activeBinding));
}
if (color.getRed() != -1 || color.getGreen() != -1 || color.getBlue() != -1) {
changedStates.add(new AbstractMap.SimpleEntry<>(
color,
color.copy()
));
} else {
color.set(glListStates.get(color));
}
if(!changedStates.isEmpty()) {
glListChanges.put(glListId, changedStates);
}
if(glListMode == GL11.GL_COMPILE) {
@@ -1566,8 +1593,9 @@ public class GLStateManager {
} else {
trySyncProgram();
GL11.glCallList(list);
if(glListChanges.containsKey(list)) {
for(Map.Entry<IStateStack<?>, ISettableState<?>> entry : glListChanges.get(list)) {
final Set<Map.Entry<IStateStack<?>, ISettableState<?>>> changes = glListChanges.get(list);
if(changes != null) {
for(Map.Entry<IStateStack<?>, ISettableState<?>> entry : changes) {
// Set the stack to the cached state at the end of the call list compilation
((ISettableState<?>)entry.getKey()).set(entry.getValue());
}
@@ -1,5 +1,22 @@
package com.gtnewhorizons.angelica.glsm.debug;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -9,14 +26,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
// Adapted from https://github.com/makamys/CoreTweaks/blob/master/src/main/java/makamys/coretweaks/util/OpenGLDebugging.java;
// originally from https://github.com/TheGreyGhost/MinecraftByExample/blob/1-8final/src/main/java/minecraftbyexample/usefultools/OpenGLdebugging.java
@@ -30,7 +39,7 @@ public class OpenGLDebugging {
public static final String GL_GET_INTEGERV = "glGetIntegerv()";
public static final String GL_GET_FLOATV = "glGetFloatv()";
public class GLproperty {
public static class GLproperty {
public GLproperty(int glConstant, String name, String description, String category, String fetchCommand) {
this.gLConstant = glConstant;
@@ -445,11 +454,12 @@ public class OpenGLDebugging {
}
}
public static void checkGLSM() {
public static String getGLSMErrorLog() {
StringBuilder error = new StringBuilder();
boolean mismatch = false;
for (int i = 0; i < instance.propertyList.length; ++i) {
final GLproperty gLProperty = instance.propertyList[i];
if(gLProperty.fetchCommand.equals(GL_GET_FLOATV) && gLProperty.name.endsWith("_MATRIX")) {
if (gLProperty.fetchCommand.equals(GL_GET_FLOATV) && gLProperty.name.endsWith("_MATRIX")) {
final Matrix4f cached = gLProperty.getAsMatrix4f(true);
final Matrix4f uncached = gLProperty.getAsMatrix4f(false);
// Some precision issues due to RAD vs degrees, and translated (vs f)
@@ -461,14 +471,87 @@ public class OpenGLDebugging {
final String cached = gLProperty.getAsString(true);
final String uncached = gLProperty.getAsString(false);
if (!cached.equals(uncached)) {
LOGGER.error("GLSM mismatch: " + gLProperty.name + " cached: " + cached + " uncached: " + uncached);
error.append("GLSM mismatch: " + gLProperty.name + " cached: " + cached + " uncached: " + uncached);
error.append('\n');
mismatch = true;
}
}
}
final TextureUnitArray textureUnits = GLStateManager.getTextures();
int currentActiveTexture = GLStateManager.getActiveTextureUnit();
for (int i = 0; i < textureUnits.textureMatricies.length; i++) {
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + i);
final boolean cached = GLStateManager.glIsEnabled(GL11.GL_TEXTURE_2D);
final boolean uncached = GL11.glIsEnabled(GL11.GL_TEXTURE_2D);
if (cached != uncached) {
error.append("GLSM mismatch: " + "GL_TEXTURE_2D" + " cached: " + cached + " uncached: " + uncached + ", texture unit: GL_TEXTURE" + i);
error.append('\n');
mismatch = true;
}
}
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + currentActiveTexture);
if (!mismatch) {
return null;
}
return error.toString();
}
public static void checkGLSM() {
String output = getGLSMErrorLog();
if (output == null) {
LOGGER.info("GLSM state matches!");
} else {
LOGGER.error(output);
}
}
public static void copyTexture(ResourceLocation resource, File output) {
Object object = Minecraft.getMinecraft().renderEngine.mapTextureObjects.get(resource);
if (object != null) {
copyTexture(((ITextureObject) object).getGlTextureId(), output);
}
}
public static void copyTexture(int textureID, File output) {
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH);
int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT);
BufferedImage bufferedimage = new BufferedImage(width, height, 1);
final int[] pixelValues = ((DataBufferInt) bufferedimage.getRaster().getDataBuffer()).getData();
IntBuffer pixelBuffer = BufferUtils.createIntBuffer(pixelValues.length);
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);
pixelBuffer.get(pixelValues);
// Flip texture
final int halfHeight = height / 2;
final int[] rowBuffer = new int[width];
for (int y = 0; y < halfHeight; y++) {
final int top = y * width;
final int bottom = (height - 1 - y) * width;
System.arraycopy(pixelValues, top, rowBuffer, 0, width);
System.arraycopy(pixelValues, bottom, pixelValues, top, width);
System.arraycopy(rowBuffer, 0, pixelValues, bottom, width);
}
File dir = output.getParentFile();
dir.mkdirs();
copyBufferedImageToFile(bufferedimage, output);
bufferedimage.flush();
}
private static void copyBufferedImageToFile(BufferedImage image, File file) {
try {
ImageIO.write(image, "png", file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -3,8 +3,6 @@ package com.gtnewhorizons.angelica.proxy;
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
import com.google.common.base.Objects;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
import com.gtnewhorizons.angelica.compat.ModStatus;
import com.gtnewhorizons.angelica.compat.bettercrashes.BetterCrashesCompat;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
@@ -12,15 +10,13 @@ import com.gtnewhorizons.angelica.config.CompatConfig;
import com.gtnewhorizons.angelica.debug.F3Direction;
import com.gtnewhorizons.angelica.debug.FrametimeGraph;
import com.gtnewhorizons.angelica.debug.TPSGraph;
import com.gtnewhorizons.angelica.mixins.interfaces.IGameSettingsExt;
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.debug.OpenGLDebugging;
import com.gtnewhorizons.angelica.hudcaching.HUDCaching;
import com.gtnewhorizons.angelica.models.VanillaModels;
import com.gtnewhorizons.angelica.mixins.interfaces.IGameSettingsExt;
import com.gtnewhorizons.angelica.render.CloudRenderer;
import com.gtnewhorizons.angelica.rendering.AngelicaBlockSafetyRegistry;
import com.gtnewhorizons.angelica.utils.AssetLoader;
import com.gtnewhorizons.angelica.zoom.Zoom;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.common.FMLCommonHandler;
@@ -39,7 +35,6 @@ import jss.notfine.core.Settings;
import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler;
import net.coderbot.iris.Iris;
import net.coderbot.iris.client.IrisDebugScreenHandler;
import net.coderbot.iris.vertices.IrisVertexFormats;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -76,7 +71,6 @@ public class ClientProxy extends CommonProxy {
FMLCommonHandler.instance().bus().register(this);
MinecraftForge.EVENT_BUS.register(this);
AssetLoader.load();
}
@SubscribeEvent
@@ -114,23 +108,6 @@ public class ClientProxy extends CommonProxy {
Iris.INSTANCE.fmlInitEvent();
FMLCommonHandler.instance().bus().register(Iris.INSTANCE);
MinecraftForge.EVENT_BUS.register(Iris.INSTANCE);
VertexFormat.registerSetupBufferStateOverride((vertexFormat, l) -> {
if (vertexFormat == DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL
|| vertexFormat == DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP) {
IrisVertexFormats.TERRAIN.setupBufferState(l);
return true;
}
return false;
});
VertexFormat.registerClearBufferStateOverride(vertexFormat -> {
if (vertexFormat == DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL
|| vertexFormat == DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP) {
IrisVertexFormats.TERRAIN.clearBufferState();
return true;
}
return false;
});
}
FMLCommonHandler.instance().bus().register(this);
@@ -139,8 +116,6 @@ public class ClientProxy extends CommonProxy {
glsmKeyBinding = new KeyBinding("Print GLSM Debug", Keyboard.KEY_NONE, "Angelica");
ClientRegistry.registerKeyBinding(glsmKeyBinding);
VanillaModels.init();
if (ModStatus.isBetterCrashesLoaded) {
BetterCrashesCompat.init();
}
@@ -23,7 +23,6 @@ package com.gtnewhorizons.angelica.render;
import com.gtnewhorizon.gtnhlib.client.renderer.CapturingTessellator;
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
import com.gtnewhorizon.gtnhlib.client.renderer.vbo.VBOManager;
import com.gtnewhorizon.gtnhlib.client.renderer.vbo.VertexBuffer;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
@@ -60,7 +59,6 @@ public class CloudRenderer implements IResourceManagerReloadListener {
private final Minecraft mc = Minecraft.getMinecraft();
private final ResourceLocation texture = new ResourceLocation("textures/environment/clouds.png");
private int displayList = -1;
private VertexBuffer vbo;
private int cloudMode = -1;
private int renderDistance = -1;
@@ -68,6 +66,7 @@ public class CloudRenderer implements IResourceManagerReloadListener {
private int scaleMult = -1;
private DynamicTexture COLOR_TEX = null;
private int texColor;
private int texW;
private int texH;
@@ -224,10 +223,7 @@ public class CloudRenderer implements IResourceManagerReloadListener {
vertices(tess);
if(displayList == -1) {
this.displayList = VBOManager.generateDisplayLists(1);
}
this.vbo = VBOManager.registerVBO(this.displayList, TessellatorManager.stopCapturingToVBO(FORMAT));
this.vbo = TessellatorManager.stopCapturingToVBO(FORMAT);
}
private int fullCoord(double coord, int scale) { // Corrects misalignment of UV offset when on negative coords.
@@ -305,7 +301,7 @@ public class CloudRenderer implements IResourceManagerReloadListener {
// Translate the texture.
GLStateManager.glMatrixMode(GL11.GL_TEXTURE);
GLStateManager.glTranslated(offU * PX_SIZE, offV * PX_SIZE, 0);
GLStateManager.glTranslatef(offU * PX_SIZE, offV * PX_SIZE, 0);
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
GLStateManager.disableCull();
@@ -328,15 +324,19 @@ public class CloudRenderer implements IResourceManagerReloadListener {
b = tempB;
}
if (COLOR_TEX == null)
COLOR_TEX = new DynamicTexture(1, 1);
// Apply a color multiplier through a texture upload if shaders aren't supported.
COLOR_TEX.getTextureData()[0] = 255 << 24
final int newColor = 0xFF000000
| ((int) (r * 255)) << 16
| ((int) (g * 255)) << 8
| (int) (b * 255);
COLOR_TEX.updateDynamicTexture();
if (texColor != newColor) {
if (COLOR_TEX == null) {
COLOR_TEX = new DynamicTexture(1, 1);
}
COLOR_TEX.getTextureData()[0] = newColor;
COLOR_TEX.updateDynamicTexture();
texColor = newColor;
}
GLStateManager.glActiveTexture(OpenGlHelper.lightmapTexUnit);
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, COLOR_TEX.getGlTextureId());
@@ -4,19 +4,30 @@ package jss.notfine.render;
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
import com.gtnewhorizon.gtnhlib.client.renderer.vbo.VBOManager;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import jss.notfine.core.Settings;
import jss.util.RandomXoshiro256StarStar;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.Tessellator;
import org.lwjgl.opengl.GL11;
public class RenderStars {
//private static final ResourceLocation locationStarsPng = new ResourceLocation("textures/colormap/stars.png");
public static void reloadStarRenderList(RenderGlobal render) {
TessellatorManager.startCapturing();
renderStars();
VBOManager.registerVBO(render.starGLCallList, TessellatorManager.stopCapturingToVBO(DefaultVertexFormat.POSITION));
if(AngelicaConfig.enableVBO) {
TessellatorManager.startCapturing();
renderStars();
VBOManager.registerVBO(render.starGLCallList, TessellatorManager.stopCapturingToVBO(DefaultVertexFormat.POSITION));
} else {
GL11.glPushMatrix();
GL11.glNewList(render.starGLCallList, GL11.GL_COMPILE);
renderStars();
GL11.glEndList();
GL11.glPopMatrix();
}
}
public static void renderStars() {
@@ -16,7 +16,8 @@ public abstract class Type {
public static final Primitive[] AllPrimitives = {Type.Boolean, Type.Int, Type.Float};
public static UniformType convert(Type type) {
if (type == Type.Int || type == Type.Boolean) return UniformType.INT;
if (type == Type.Int) return UniformType.INT;
else if (type == Type.Boolean) return UniformType.INT;
else if (type == Type.Float) return UniformType.FLOAT;
else if (type == VectorType.VEC2) return UniformType.VEC2;
else if (type == VectorType.VEC3) return UniformType.VEC3;
@@ -28,6 +28,7 @@ import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCache
import me.jellysquid.mods.sodium.client.util.math.FrustumExtended;
import me.jellysquid.mods.sodium.common.util.ListUtil;
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
import net.coderbot.iris.gl.shader.ProgramCreator;
import net.coderbot.iris.layer.GbufferPrograms;
import net.coderbot.iris.pipeline.ShadowRenderer;
import net.coderbot.iris.shadows.ShadowRenderingState;
@@ -51,6 +52,7 @@ import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraftforge.client.MinecraftForgeClient;
import org.joml.Vector3d;
import org.lwjgl.opengl.GL20;
import java.util.Set;
@@ -359,6 +361,9 @@ public class SodiumWorldRenderer {
if(AngelicaConfig.enableIris) {
final Block block = tileEntity.getWorldObj().getBlock(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord);
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(Block.getIdFromBlock(block));
GL20.glVertexAttrib2s(ProgramCreator.MC_ENTITY, (short)-1, (short)-1);
GL20.glVertexAttrib2f(ProgramCreator.MC_MID_TEX_COORD, 0.5f, 0.5f);
GL20.glVertexAttrib4f(ProgramCreator.AT_TANGENT, 1.0f, 0.0f, 0.0f, 1.0f);
GbufferPrograms.beginBlockEntities();
}
TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks);
@@ -203,43 +203,45 @@ public class ProgramUniforms {
final int size = sizeType.get(0);
final int type = sizeType.get(1);
UniformType provided = uniformNames.get(name);
final UniformType provided = uniformNames.get(name);
final UniformType expected = getExpectedType(type);
if (provided == null && !name.startsWith("gl_")) {
final String typeName = getTypeName(type);
if(AngelicaConfig.enableHardcodedCustomUniforms) {
// Legacy Checks from hardcoded custom uniforms
if (provided == null && !name.startsWith("gl_")) {
final String typeName = getTypeName(type);
if (isSampler(type) || isImage(type)) {
// don't print a warning, samplers and images are managed elsewhere.
// TODO: Detect unsupported samplers/images?
continue;
}
if (isSampler(type) || isImage(type)) {
// don't print a warning, samplers and images are managed elsewhere.
continue;
}
final UniformType externalProvided = externalUniformNames.get(name);
final UniformType externalProvided = externalUniformNames.get(name);
if (externalProvided != null) {
if (externalProvided != expected) {
String expectedName;
if (externalProvided != null) {
if (externalProvided != expected) {
final String expectedName;
if (expected != null) {
expectedName = expected.toString();
} else {
expectedName = "(unsupported type: " + getTypeName(type) + ")";
if (expected != null) {
expectedName = expected.toString();
} else {
expectedName = "(unsupported type: " + getTypeName(type) + ")";
}
Iris.logger.error("[" + this.name + "] Wrong uniform type for externally-managed uniform " + name + ": " + externalProvided + " is provided but the program expects " + expectedName + ".");
}
Iris.logger.error("[" + this.name + "] Wrong uniform type for externally-managed uniform " + name + ": " + externalProvided + " is provided but the program expects " + expectedName + ".");
continue;
}
if (size == 1) {
Iris.logger.warn("[" + this.name + "] Unsupported uniform: " + typeName + " " + name);
} else {
Iris.logger.warn("[" + this.name + "] Unsupported uniform: " + name + " of size " + size + " and type " + typeName);
}
continue;
}
if (size == 1) {
Iris.logger.warn("[" + this.name + "] Unsupported uniform: " + typeName + " " + name);
} else {
Iris.logger.warn("[" + this.name + "] Unsupported uniform: " + name + " of size " + size + " and type " + typeName);
}
continue;
}
if (provided != null && provided != expected) {
@@ -291,6 +293,7 @@ public class ProgramUniforms {
return switch(type) {
case GL11.GL_FLOAT -> "float";
case GL11.GL_INT -> "int";
case GL20.GL_BOOL -> "bool";
case GL20.GL_FLOAT_MAT4 -> "mat4";
case GL20.GL_FLOAT_VEC4 -> "vec4";
case GL20.GL_FLOAT_MAT3 -> "mat3";
@@ -316,12 +319,13 @@ public class ProgramUniforms {
return switch (type) {
case GL11.GL_FLOAT -> UniformType.FLOAT;
case GL11.GL_INT -> UniformType.INT;
case GL20.GL_BOOL -> UniformType.INT;
case GL20.GL_FLOAT_MAT4 -> UniformType.MAT4;
case GL20.GL_FLOAT_VEC4 -> UniformType.VEC4;
case GL20.GL_INT_VEC4 -> UniformType.VEC4I;
case GL20.GL_FLOAT_VEC3 -> UniformType.VEC3;
case GL20.GL_FLOAT_MAT3 -> null;
case GL20.GL_INT_VEC3 -> null;
case GL20.GL_FLOAT_MAT3 -> UniformType.MAT3;
case GL20.GL_INT_VEC3 -> UniformType.VEC3I;
case GL20.GL_FLOAT_MAT2 -> null;
case GL20.GL_FLOAT_VEC2 -> UniformType.VEC2;
case GL20.GL_INT_VEC2 -> UniformType.VEC2I;
@@ -11,16 +11,22 @@ import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.KHRDebug;
public class ProgramCreator {
private static final Logger LOGGER = LogManager.getLogger(ProgramCreator.class);
public static final int MC_ENTITY = 11;
public static final int MC_MID_TEX_COORD = 12;
public static final int AT_TANGENT = 13;
public static final int AT_MIDBLOCK = 14;
public static int create(String name, GlShader... shaders) {
int program = GL20.glCreateProgram();
// TODO: This is *really* hardcoded, we need to refactor this to support external calls to glBindAttribLocation
RenderSystem.bindAttributeLocation(program, 11, "mc_Entity");
RenderSystem.bindAttributeLocation(program, 12, "mc_midTexCoord");
RenderSystem.bindAttributeLocation(program, 13, "at_tangent");
RenderSystem.bindAttributeLocation(program, 14, "at_midBlock");
RenderSystem.bindAttributeLocation(program, MC_ENTITY, "mc_Entity");
RenderSystem.bindAttributeLocation(program, MC_MID_TEX_COORD, "mc_midTexCoord");
RenderSystem.bindAttributeLocation(program, AT_TANGENT, "at_tangent");
RenderSystem.bindAttributeLocation(program, AT_MIDBLOCK, "at_midBlock");
for (GlShader shader : shaders) {
GL20.glAttachShader(program, shader.getHandle());
@@ -3,11 +3,13 @@ package net.coderbot.iris.gl.shader;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizons.angelica.Tags;
import cpw.mods.fml.common.Loader;
import net.coderbot.iris.parsing.BiomeCategories;
import net.coderbot.iris.pipeline.HandRenderer;
import net.coderbot.iris.pipeline.WorldRenderingPhase;
import net.coderbot.iris.shaderpack.StringPair;
import net.coderbot.iris.texture.format.TextureFormat;
import net.coderbot.iris.texture.format.TextureFormatLoader;
import net.coderbot.iris.uniforms.VanillaBiomeList;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
@@ -88,6 +90,9 @@ public class StandardMacros {
define(standardDefines, irisDefine);
}
getBiomeCategoryDefines().forEach((category, ordinal) -> define(standardDefines, category, ordinal));
getVanillaBiomeDefines().forEach((biome, id) -> define(standardDefines, biome, id));
return ImmutableList.copyOf(standardDefines);
}
@@ -98,7 +103,7 @@ public class StandardMacros {
* @see <a href="https://github.com/sp614x/optifine/blob/9c6a5b5326558ccc57c6490b66b3be3b2dc8cbef/OptiFineDoc/doc/shaders.txt#L696-L699">Optifine Doc</a>
*/
public static String getMcVersion() {
final String version = Loader.MC_VERSION;;
final String version = Loader.MC_VERSION;
String[] splitVersion = version.split("\\.");
@@ -117,10 +122,10 @@ public class StandardMacros {
}
if (minor.length() == 1) {
minor = 0 + minor;
minor = "0" + minor;
}
if (bugfix.length() == 1) {
bugfix = 0 + bugfix;
bugfix = "0" + bugfix;
}
return major + minor + bugfix;
@@ -283,4 +288,47 @@ public class StandardMacros {
return defines;
}
/**
* Returns biome category defines for use in shaders.
* Generates #define CAT_<CATEGORY_NAME> <ordinal> for each BiomeCategories enum value.
*
* @return Map of biome category defines and their ordinal values
*/
public static Map<String, String> getBiomeCategoryDefines() {
Map<String, String> defines = new HashMap<>();
for (BiomeCategories category : BiomeCategories.values()) {
defines.put("CAT_" + category.name(), String.valueOf(category.ordinal()));
}
return defines;
}
/**
* Returns vanilla biome ID defines for use in shaders.
* Generates #define BIOME_<BIOME_NAME> <biomeID> for all vanilla biomes.
*
* @return Map of vanilla biome defines and their IDs
*/
public static Map<String, String> getVanillaBiomeDefines() {
final Map<String, String> defines = new HashMap<>();
for (VanillaBiomeList.BiomeEntry entry : VanillaBiomeList.getVanillaBiomes()) {
if (entry.biome != null) {
defines.put("BIOME_" + entry.name, String.valueOf(entry.biome.biomeID));
}
}
// Modern biomes that don't exist in 1.7.10 - add dummy IDs that will never match
// This allows shader expressions to parse without errors while always evaluating to false/0
// Using negative IDs to avoid conflicts with actual biome IDs
defines.put("BIOME_NETHER_WASTES", "-1000");
defines.put("BIOME_SOUL_SAND_VALLEY", "-1001");
defines.put("BIOME_CRIMSON_FOREST", "-1002");
defines.put("BIOME_WARPED_FOREST", "-1003");
defines.put("BIOME_BASALT_DELTAS", "-1004");
defines.put("BIOME_LUSH_CAVES", "-1005");
defines.put("BIOME_PALE_GARDEN", "-1006");
return defines;
}
}
@@ -2,7 +2,9 @@ package net.coderbot.iris.gl.uniform;
public enum UniformType {
INT,
BOOL,
FLOAT,
MAT3,
MAT4,
VEC2,
VEC2I,
@@ -1,6 +1,7 @@
package net.coderbot.iris.pipeline;
import com.gtnewhorizons.angelica.compat.mojang.Camera;
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
import com.gtnewhorizons.angelica.compat.mojang.InteractionHand;
import com.gtnewhorizons.angelica.compat.toremove.RenderLayer;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
@@ -26,7 +27,7 @@ public class HandRenderer {
public static final float DEPTH = 0.125F;
private void setupGlState(RenderGlobal gameRenderer, Camera camera, float tickDelta) {
Minecraft mc = Minecraft.getMinecraft();
final Minecraft mc = Minecraft.getMinecraft();
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
@@ -72,8 +73,7 @@ public class HandRenderer {
mc.gameSettings.thirdPersonView == 0 &&
!camera.getEntity().isPlayerSleeping() &&
!mc.gameSettings.hideGUI &&
// TODO: SPECTATOR
// mc.playerController.currentGameType
!GameModeUtil.isSpectator() &&
!mc.playerController.enableEverythingIsScrewedUpMode();
}
@@ -9,6 +9,7 @@ import net.coderbot.iris.pipeline.transform.TransformPatcher;
import net.coderbot.iris.shaderpack.ProgramSet;
import net.coderbot.iris.shaderpack.ProgramSource;
import net.coderbot.iris.uniforms.CommonUniforms;
import net.coderbot.iris.uniforms.ExternallyManagedUniforms;
import net.coderbot.iris.uniforms.builtin.BuiltinReplacementUniforms;
import net.coderbot.iris.uniforms.custom.CustomUniforms;
@@ -143,6 +144,8 @@ public class SodiumTerrainPipeline {
CommonUniforms.addDynamicUniforms(uniforms);
customUniforms.assignTo(uniforms);
ExternallyManagedUniforms.addExternallyManagedUniforms116(uniforms);
BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniforms);
return uniforms;
}
@@ -18,13 +18,17 @@ import net.coderbot.iris.gl.blending.BlendModeFunction;
import net.coderbot.iris.gl.blending.BlendModeOverride;
import net.coderbot.iris.gl.blending.BufferBlendInformation;
import net.coderbot.iris.gl.texture.TextureScaleOverride;
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
import net.coderbot.iris.shaderpack.option.ShaderPackOptions;
import net.coderbot.iris.shaderpack.preprocessor.PropertiesPreprocessor;
import net.coderbot.iris.shaderpack.texture.TextureStage;
import net.coderbot.iris.uniforms.custom.CustomUniforms;
import net.minecraft.client.Minecraft;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
@@ -98,6 +102,15 @@ public class ShaderProperties {
public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, Iterable<StringPair> environmentDefines) {
final String preprocessedContents = PropertiesPreprocessor.preprocessSource(contents, shaderPackOptions, environmentDefines);
if (PatchedShaderPrinter.prettyPrintShaders) {
try {
Files.write(Minecraft.getMinecraft().mcDataDir.toPath().resolve("preprocessed.properties"), preprocessedContents.getBytes(StandardCharsets.UTF_8));
Files.write(Minecraft.getMinecraft().mcDataDir.toPath().resolve("original.properties"), contents.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
final Properties preprocessed = new OrderBackedProperties();
final Properties original = new OrderBackedProperties();
try {
@@ -181,7 +194,7 @@ public class ShaderProperties {
});
handlePassDirective("alphaTest.", key, value, pass -> {
if ("off".equals(value)) {
if ("off".equals(value) || "false".equals(value)) {
alphaTestOverrides.put(pass, AlphaTestOverride.OFF);
return;
}
@@ -6,6 +6,7 @@ import net.coderbot.iris.shaderpack.option.ShaderPackOptions;
import org.anarres.cpp.Feature;
import org.anarres.cpp.LexerException;
import org.anarres.cpp.Preprocessor;
import org.anarres.cpp.PreprocessorCommand;
import org.anarres.cpp.StringLexerSource;
import org.anarres.cpp.Token;
@@ -14,18 +15,19 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
public class PropertiesPreprocessor {
// Derived from ShaderProcessor.glslPreprocessSource, which is derived from GlShader from Canvas, licenced under LGPL
public static String preprocessSource(String source, ShaderPackOptions shaderPackOptions, Iterable<StringPair> environmentDefines) {
if (source.contains(PropertyCollectingListener.PROPERTY_MARKER)) {
if (source.contains(PropertyCollectingListener.PROPERTY_MARKER) || source.contains("IRIS_PASSTHROUGHBACKSLASH")) {
throw new RuntimeException("Some shader author is trying to exploit internal Iris implementation details, stop!");
}
List<String> booleanValues = getBooleanValues(shaderPackOptions);
Map<String, String> stringValues = getStringValues(shaderPackOptions);
final List<String> booleanValues = getBooleanValues(shaderPackOptions);
final Map<String, String> stringValues = getStringValues(shaderPackOptions);
try (Preprocessor pp = new Preprocessor()) {
for (String value : booleanValues) {
@@ -57,7 +59,7 @@ public class PropertiesPreprocessor {
throw new RuntimeException("Some shader author is trying to exploit internal Iris implementation details, stop!");
}
Preprocessor preprocessor = new Preprocessor();
final Preprocessor preprocessor = new Preprocessor();
try {
for (StringPair envDefine : environmentDefines) {
@@ -78,19 +80,23 @@ public class PropertiesPreprocessor {
// Not super efficient, but this removes trailing whitespace on lines, fixing an issue with whitespace after
// line continuations (see PreprocessorTest#testWeirdPropertiesLineContinuation)
// Required for Voyager Shader
source = Arrays.stream(source.split("\\R")).map(String::trim)
source = Arrays.stream(source.split("\\R")).map(String::trim).filter(s -> !s.isEmpty())
.map(line -> {
if (line.startsWith("#")) {
// In PropertyCollectingListener we suppress "unknown preprocessor directive errors" and
// assume the line to be a comment, since in .properties files `#` also functions as a comment
// marker.
return line;
} else {
// This is a hack to ensure that non-macro lines don't have any preprocessing applied...
// In properties files, we don't substitute #define values except on macro lines.
return "#warning IRIS_PASSTHROUGH " + line;
for (PreprocessorCommand command : PreprocessorCommand.values()) {
if (line.startsWith("#" + (command.name().replace("PP_", "").toLowerCase(Locale.ROOT)))) {
return line;
}
}
return "";
}
// In PropertyCollectingListener we suppress "unknown preprocessor directive errors" and
// assume the line to be a comment, since in .properties files `#` also functions as a comment
// marker.
return line.replace("#", "");
}).collect(Collectors.joining("\n")) + "\n";
// TODO: This is a horrible fix to trick the preprocessor into not seeing the backslashes during processing. We need a better way to do this.
source = source.replace("\\", "IRIS_PASSTHROUGHBACKSLASH");
preprocessor.addInput(new StringLexerSource(source, true));
preprocessor.addFeature(Feature.KEEPCOMMENTS);
@@ -110,7 +116,7 @@ public class PropertiesPreprocessor {
source = builder.toString();
return listener.collectLines() + source;
return (listener.collectLines() + source).replace("IRIS_PASSTHROUGHBACKSLASH", "\\");
}
private static List<String> getBooleanValues(ShaderPackOptions shaderPackOptions) {
@@ -1,95 +0,0 @@
package net.coderbot.iris.sodium.vertex_format.entity_xhfp;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterNio;
import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink;
import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink;
import me.jellysquid.mods.sodium.client.util.Norm3b;
import net.coderbot.iris.vertices.IrisVertexFormats;
import net.coderbot.iris.vertices.NormalHelper;
import org.joml.Vector3f;
import java.nio.ByteBuffer;
public class EntityVertexBufferWriterNio extends VertexBufferWriterNio implements QuadVertexSink, GlyphVertexSink {
private static final int STRIDE = IrisVertexFormats.ENTITY.getVertexSize();
private final QuadViewEntity.QuadViewEntityNio quad = new QuadViewEntity.QuadViewEntityNio();
private final Vector3f saveNormal = new Vector3f();
private int vertexCount;
private float uSum;
private float vSum;
public EntityVertexBufferWriterNio(VertexBufferView backingBuffer) {
super(backingBuffer, ExtendedQuadVertexType.INSTANCE);
}
@Override
public void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) {
int i = this.writeOffset;
ByteBuffer buffer = this.byteBuffer;
vertexCount++;
uSum += u;
vSum += v;
buffer.putFloat(i, x);
buffer.putFloat(i + 4, y);
buffer.putFloat(i + 8, z);
buffer.putInt(i + 12, color);
buffer.putFloat(i + 16, u);
buffer.putFloat(i + 20, v);
buffer.putInt(i + 24, overlay);
buffer.putInt(i + 28, light);
if (vertexCount == 4) {
this.endQuad(normal);
}
this.advance();
}
@Override
public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) {
writeQuad(x, y, z, color, u, v, light, 0, 0);
}
private void endQuad(int normal) {
this.vertexCount = 0;
int i = this.writeOffset;
ByteBuffer buffer = this.byteBuffer;
uSum *= 0.25;
vSum *= 0.25;
quad.setup(buffer, i, STRIDE);
float normalX, normalY, normalZ;
if (normal == 0) {
NormalHelper.computeFaceNormal(saveNormal, quad);
normalX = saveNormal.x;
normalY = saveNormal.y;
normalZ = saveNormal.z;
normal = NormalHelper.packNormal(saveNormal, 0.0F);
} else {
normalX = Norm3b.unpackX(normal);
normalY = Norm3b.unpackY(normal);
normalZ = Norm3b.unpackZ(normal);
}
int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad);
for (int vertex = 0; vertex < 4; vertex++) {
buffer.putFloat(i + 36 - STRIDE * vertex, uSum);
buffer.putFloat(i + 40 - STRIDE * vertex, vSum);
buffer.putInt(i + 32 - STRIDE * vertex, normal);
buffer.putInt(i + 44 - STRIDE * vertex, tangent);
}
uSum = 0;
vSum = 0;
}
}
@@ -1,93 +0,0 @@
package net.coderbot.iris.sodium.vertex_format.entity_xhfp;
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.*;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterUnsafe;
import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink;
import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink;
import me.jellysquid.mods.sodium.client.util.Norm3b;
import net.coderbot.iris.vertices.IrisVertexFormats;
import net.coderbot.iris.vertices.NormalHelper;
import org.joml.Vector3f;
public class EntityVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink, GlyphVertexSink {
private static final int STRIDE = IrisVertexFormats.ENTITY.getVertexSize();
private final QuadViewEntity.QuadViewEntityUnsafe quad = new QuadViewEntity.QuadViewEntityUnsafe();
private final Vector3f saveNormal = new Vector3f();
private int vertexCount;
private float uSum;
private float vSum;
public EntityVertexBufferWriterUnsafe(VertexBufferView backingBuffer) {
super(backingBuffer, ExtendedQuadVertexType.INSTANCE);
}
@Override
public void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) {
long i = this.writePointer;
vertexCount++;
uSum += u;
vSum += v;
memPutFloat(i, x);
memPutFloat(i + 4, y);
memPutFloat(i + 8, z);
memPutInt(i + 12, color);
memPutFloat(i + 16, u);
memPutFloat(i + 20, v);
memPutInt(i + 24, overlay);
memPutInt(i + 28, light);
if (vertexCount == 4) {
this.endQuad(normal);
}
this.advance();
}
@Override
public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) {
writeQuad(x, y, z, color, u, v, light, 0, 0);
}
private void endQuad(int normal) {
this.vertexCount = 0;
long i = this.writePointer;
uSum *= 0.25;
vSum *= 0.25;
quad.setup(writePointer, STRIDE);
float normalX, normalY, normalZ;
if (normal == 0) {
NormalHelper.computeFaceNormal(saveNormal, quad);
normalX = saveNormal.x;
normalY = saveNormal.y;
normalZ = saveNormal.z;
normal = NormalHelper.packNormal(saveNormal, 0.0F);
} else {
normalX = Norm3b.unpackX(normal);
normalY = Norm3b.unpackY(normal);
normalZ = Norm3b.unpackZ(normal);
}
int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad);
for (long vertex = 0; vertex < 4; vertex++) {
memPutFloat(i + 36 - STRIDE * vertex, uSum);
memPutFloat(i + 40 - STRIDE * vertex, vSum);
memPutInt(i + 32 - STRIDE * vertex, normal);
memPutInt(i + 44 - STRIDE * vertex, tangent);
}
uSum = 0;
vSum = 0;
}
}
@@ -1,34 +0,0 @@
package net.coderbot.iris.sodium.vertex_format.entity_xhfp;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView;
import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink;
import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexWriterFallback;
import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType;
import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType;
import net.coderbot.iris.vertices.IrisVertexFormats;
public class ExtendedGlyphVertexType implements VanillaVertexType<GlyphVertexSink>, BlittableVertexType<GlyphVertexSink> {
public static final ExtendedGlyphVertexType INSTANCE = new ExtendedGlyphVertexType();
@Override
public GlyphVertexSink createFallbackWriter(VertexConsumer vertexConsumer) {
return new GlyphVertexWriterFallback(vertexConsumer);
}
@Override
public GlyphVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) {
return direct ? new GlyphVertexBufferWriterUnsafe(buffer) : new GlyphVertexBufferWriterNio(buffer);
}
@Override
public VertexFormat getVertexFormat() {
return IrisVertexFormats.TERRAIN;
}
public BlittableVertexType<GlyphVertexSink> asBlittable() {
return this;
}
}
@@ -1,34 +0,0 @@
package net.coderbot.iris.sodium.vertex_format.entity_xhfp;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView;
import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink;
import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexWriterFallback;
import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType;
import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType;
import net.coderbot.iris.vertices.IrisVertexFormats;
public class ExtendedQuadVertexType implements VanillaVertexType<QuadVertexSink>, BlittableVertexType<QuadVertexSink> {
public static final ExtendedQuadVertexType INSTANCE = new ExtendedQuadVertexType();
@Override
public QuadVertexSink createFallbackWriter(VertexConsumer vertexConsumer) {
return new QuadVertexWriterFallback(vertexConsumer);
}
@Override
public QuadVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) {
return direct ? new EntityVertexBufferWriterUnsafe(buffer) : new EntityVertexBufferWriterNio(buffer);
}
@Override
public VertexFormat getVertexFormat() {
return IrisVertexFormats.ENTITY;
}
public BlittableVertexType<QuadVertexSink> asBlittable() {
return this;
}
}
@@ -1,94 +0,0 @@
package net.coderbot.iris.sodium.vertex_format.entity_xhfp;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterNio;
import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink;
import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink;
import me.jellysquid.mods.sodium.client.util.Norm3b;
import net.coderbot.iris.vertices.IrisVertexFormats;
import net.coderbot.iris.vertices.NormalHelper;
import org.joml.Vector3f;
import java.nio.ByteBuffer;
public class GlyphVertexBufferWriterNio extends VertexBufferWriterNio implements QuadVertexSink, GlyphVertexSink {
private static final int STRIDE = IrisVertexFormats.TERRAIN.getVertexSize();
private final QuadViewEntity.QuadViewEntityNio quad = new QuadViewEntity.QuadViewEntityNio();
private final Vector3f saveNormal = new Vector3f();
private int vertexCount;
private float uSum;
private float vSum;
public GlyphVertexBufferWriterNio(VertexBufferView backingBuffer) {
super(backingBuffer, ExtendedGlyphVertexType.INSTANCE);
}
@Override
public void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) {
int i = this.writeOffset;
ByteBuffer buffer = this.byteBuffer;
vertexCount++;
uSum += u;
vSum += v;
buffer.putFloat(i, x);
buffer.putFloat(i + 4, y);
buffer.putFloat(i + 8, z);
buffer.putInt(i + 12, color);
buffer.putFloat(i + 16, u);
buffer.putFloat(i + 20, v);
buffer.putInt(i + 24, light);
if (vertexCount == 4) {
this.endQuad(normal);
}
this.advance();
}
@Override
public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) {
writeQuad(x, y, z, color, u, v, light, 0, 0);
}
private void endQuad(int normal) {
this.vertexCount = 0;
int i = this.writeOffset;
ByteBuffer buffer = this.byteBuffer;
uSum *= 0.25;
vSum *= 0.25;
quad.setup(byteBuffer, writeOffset, STRIDE);
float normalX, normalY, normalZ;
if (normal == 0) {
NormalHelper.computeFaceNormal(saveNormal, quad);
normalX = saveNormal.x;
normalY = saveNormal.y;
normalZ = saveNormal.z;
normal = NormalHelper.packNormal(saveNormal, 0.0F);
} else {
normalX = Norm3b.unpackX(normal);
normalY = Norm3b.unpackY(normal);
normalZ = Norm3b.unpackZ(normal);
}
int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad);
for (int vertex = 0; vertex < 4; vertex++) {
buffer.putFloat(i + 36 - STRIDE * vertex, uSum);
buffer.putFloat(i + 40 - STRIDE * vertex, vSum);
buffer.putInt(i + 28 - STRIDE * vertex, normal);
buffer.putInt(i + 44 - STRIDE * vertex, tangent);
}
uSum = 0;
vSum = 0;
}
}
@@ -1,92 +0,0 @@
package net.coderbot.iris.sodium.vertex_format.entity_xhfp;
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.*;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView;
import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterUnsafe;
import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink;
import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink;
import me.jellysquid.mods.sodium.client.util.Norm3b;
import net.coderbot.iris.vertices.IrisVertexFormats;
import net.coderbot.iris.vertices.NormalHelper;
import org.joml.Vector3f;
public class GlyphVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink, GlyphVertexSink {
private static final int STRIDE = IrisVertexFormats.TERRAIN.getVertexSize();
private final QuadViewEntity.QuadViewEntityUnsafe quad = new QuadViewEntity.QuadViewEntityUnsafe();
private final Vector3f saveNormal = new Vector3f();
private int vertexCount;
private float uSum;
private float vSum;
public GlyphVertexBufferWriterUnsafe(VertexBufferView backingBuffer) {
super(backingBuffer, ExtendedGlyphVertexType.INSTANCE);
}
@Override
public void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) {
long i = this.writePointer;
vertexCount++;
uSum += u;
vSum += v;
memPutFloat(i, x);
memPutFloat(i + 4, y);
memPutFloat(i + 8, z);
memPutInt(i + 12, color);
memPutFloat(i + 16, u);
memPutFloat(i + 20, v);
memPutInt(i + 24, light);
if (vertexCount == 4) {
this.endQuad(normal);
}
this.advance();
}
@Override
public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) {
writeQuad(x, y, z, color, u, v, light, 0, 0);
}
private void endQuad(int normal) {
this.vertexCount = 0;
long i = this.writePointer;
uSum *= 0.25;
vSum *= 0.25;
quad.setup(writePointer, STRIDE);
float normalX, normalY, normalZ;
if (normal == 0) {
NormalHelper.computeFaceNormal(saveNormal, quad);
normalX = saveNormal.x;
normalY = saveNormal.y;
normalZ = saveNormal.z;
normal = NormalHelper.packNormal(saveNormal, 0.0F);
} else {
normalX = Norm3b.unpackX(normal);
normalY = Norm3b.unpackY(normal);
normalZ = Norm3b.unpackZ(normal);
}
int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad);
for (long vertex = 0; vertex < 4; vertex++) {
memPutFloat(i + 36 - STRIDE * vertex, uSum);
memPutFloat(i + 40 - STRIDE * vertex, vSum);
memPutInt(i + 28 - STRIDE * vertex, normal);
memPutInt(i + 44 - STRIDE * vertex, tangent);
}
uSum = 0;
vSum = 0;
}
}
@@ -1,7 +1,7 @@
package net.coderbot.iris.texture.pbr;
import net.coderbot.iris.Iris;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.Nullable;
import java.net.URI;
@@ -32,13 +32,13 @@ public enum PBRType {
public ResourceLocation appendToFileLocation(ResourceLocation location) {
String domain = location.getResourceDomain();
String path = location.getResourcePath();
String newPath;
try {
URI uri = new URI(null, null, path, null);
String cleanPath = uri.getPath();
String newPath;
int extensionIndex = FilenameUtils.indexOfExtension(cleanPath);
int extensionIndex = safeIndexOfExtension(cleanPath);
if (extensionIndex != -1) {
newPath = cleanPath.substring(0, extensionIndex) + suffix + cleanPath.substring(extensionIndex);
} else {
@@ -48,17 +48,11 @@ public enum PBRType {
URI newUri = new URI(null, null, newPath, null);
newPath = newUri.getPath();
return new ResourceLocation(domain, newPath);
} catch (URISyntaxException e) {
String fallback = path.replace(':', '/');
int extensionIndex = FilenameUtils.indexOfExtension(fallback);
if (extensionIndex != -1) {
newPath = fallback.substring(0, extensionIndex) + suffix + fallback.substring(extensionIndex);
} else {
newPath = fallback + suffix;
}
Iris.logger.error("Failed to append PBR suffix to resource location for " + path, e);
return location;
}
return new ResourceLocation(domain, newPath);
}
/**
@@ -76,4 +70,19 @@ public enum PBRType {
}
return null;
}
// Helper method to safely find the index of the file extension
// Using this to avoid issues with ':' in paths (any block with meta).
private static int safeIndexOfExtension(String input) {
if (input == null) return -1;
// Avoid dots in directory names or leading/trailing dots
int lastSlash = Math.max(input.lastIndexOf('/'), input.lastIndexOf('\\'));
int nameStart = lastSlash + 1;
int lastDot = input.lastIndexOf('.');
if (lastDot == -1 || lastDot <= nameStart || lastDot == input.length() - 1) {
return -1;
}
return lastDot;
}
}
@@ -0,0 +1,369 @@
package net.coderbot.iris.uniforms;
import com.gtnewhorizons.angelica.compat.iris.BiomeCategoryCache;
import com.gtnewhorizons.angelica.compat.iris.ModdedBiomeDetector;
import net.coderbot.iris.gl.uniform.UniformHolder;
import net.coderbot.iris.parsing.BiomeCategories;
import net.minecraft.client.Minecraft;
import net.minecraft.util.MathHelper;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.biome.BiomeGenBeach;
import net.minecraft.world.biome.BiomeGenDesert;
import net.minecraft.world.biome.BiomeGenEnd;
import net.minecraft.world.biome.BiomeGenForest;
import net.minecraft.world.biome.BiomeGenHell;
import net.minecraft.world.biome.BiomeGenHills;
import net.minecraft.world.biome.BiomeGenJungle;
import net.minecraft.world.biome.BiomeGenMesa;
import net.minecraft.world.biome.BiomeGenMushroomIsland;
import net.minecraft.world.biome.BiomeGenMutated;
import net.minecraft.world.biome.BiomeGenOcean;
import net.minecraft.world.biome.BiomeGenPlains;
import net.minecraft.world.biome.BiomeGenRiver;
import net.minecraft.world.biome.BiomeGenSavanna;
import net.minecraft.world.biome.BiomeGenSnow;
import net.minecraft.world.biome.BiomeGenStoneBeach;
import net.minecraft.world.biome.BiomeGenSwamp;
import net.minecraft.world.biome.BiomeGenTaiga;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.HashMap;
import java.util.Map;
import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_TICK;
public class BiomeUniforms {
private static final Logger LOGGER = LogManager.getLogger("BiomeUniforms");
private static final Minecraft client = Minecraft.getMinecraft();
// Cache to avoid multiple biome lookups per tick
private static BiomeGenBase cachedBiome = null;
private static long cachedWorldTime = -1;
private static int cachedPlayerX = Integer.MIN_VALUE;
private static int cachedPlayerZ = Integer.MIN_VALUE;
/**
* Adds biome-related uniforms that change based on the player's current biome.
*/
public static void addBiomeUniforms(UniformHolder uniforms) {
uniforms.uniform1i(PER_TICK, "biome", BiomeUniforms::getBiomeId)
.uniform1i(PER_TICK, "biome_category", BiomeUniforms::getBiomeCategory)
.uniform1i(PER_TICK, "biome_precipitation", BiomeUniforms::getBiomePrecipitation)
.uniform1f(PER_TICK, "rainfall", BiomeUniforms::getBiomeRainfall)
.uniform1f(PER_TICK, "temperature", BiomeUniforms::getBiomeTemperature);
}
/**
* Gets the current biome, with caching to avoid repeated lookups within the same tick.
* Returns null if player or world is not available.
*/
private static BiomeGenBase getCachedBiome() {
if (client.thePlayer == null || client.theWorld == null) {
return null;
}
final long worldTime = client.theWorld.getTotalWorldTime();
final int playerX = MathHelper.floor_double(client.thePlayer.posX);
final int playerZ = MathHelper.floor_double(client.thePlayer.posZ);
// Invalidate cache if time or position changed
if (cachedBiome == null || cachedWorldTime != worldTime || cachedPlayerX != playerX || cachedPlayerZ != playerZ) {
cachedBiome = client.theWorld.getBiomeGenForCoords(playerX, playerZ);
cachedWorldTime = worldTime;
cachedPlayerX = playerX;
cachedPlayerZ = playerZ;
}
return cachedBiome;
}
public static int getBiomePrecipitation() {
final BiomeGenBase biome = getCachedBiome();
if (biome == null) {
return 0;
}
if (!biome.enableRain && !biome.enableSnow) {
return 0;
}
final float temp = biome.getFloatTemperature(
MathHelper.floor_double(client.thePlayer.posX),
MathHelper.floor_double(client.thePlayer.posY),
MathHelper.floor_double(client.thePlayer.posZ));
return temp > 0.15F ? 1 : 2;
}
public static float getBiomeRainfall() {
final BiomeGenBase biome = getCachedBiome();
return biome != null ? biome.rainfall : 0.0F;
}
public static float getBiomeTemperature() {
final BiomeGenBase biome = getCachedBiome();
return biome != null ? biome.temperature : 0.0F;
}
public static int getBiomeId() {
final BiomeGenBase biome = getCachedBiome();
return biome != null ? biome.biomeID : 0;
}
public static int getBiomeCategory() {
final BiomeGenBase biome = getCachedBiome();
if (biome == null) {
return BiomeCategories.NONE.ordinal();
}
// Check cache first
if (biome instanceof BiomeCategoryCache cache) {
final int cached = cache.iris$getCachedCategory();
if (cached != -1) {
return cached;
}
// Not cached yet, determine and cache it
final int category = determineBiomeCategory(biome);
cache.iris$setCachedCategory(category);
final BiomeCategories[] categories = BiomeCategories.values();
final String categoryName = (category >= 0 && category < categories.length)
? categories[category].name()
: "INVALID(" + category + ")";
LOGGER.debug("Cached biome category for '{}': {}", biome.biomeName, categoryName);
return category;
}
// Fallback if mixin didn't apply (shouldn't happen)
return determineBiomeCategory(biome);
}
private static int determineBiomeCategory(BiomeGenBase biome) {
// Tier 1: Hardcoded vanilla biome IDs
BiomeGenBase lookupBiome = biome;
if (biome instanceof BiomeGenMutated mutated && mutated.baseBiome != null) {
lookupBiome = mutated.baseBiome;
}
BiomeCategories category = getVanillaBiomeCategory(lookupBiome.biomeID);
if (category != null) {
return category.ordinal();
}
// Tier 2: Class-based detection for vanilla biome types
category = detectVanillaBiomeByClass(biome);
if (category != null) {
return category.ordinal();
}
// Tier 3: Modded biome detection (BiomesOPlenty, Realistic World Gen)
category = detectModdedBiome(biome);
if (category != null) {
return category.ordinal();
}
// Tier 4: Name pattern matching
category = detectBiomeByName(biome);
if (category != null) {
return category.ordinal();
}
// Tier 5: Temperature/rainfall heuristics
category = detectBiomeByProperties(biome);
if (category != null) {
return category.ordinal();
}
// Default: NONE
return BiomeCategories.NONE.ordinal();
}
private static BiomeCategories getVanillaBiomeCategory(int biomeID) {
return switch (biomeID) {
// OCEAN
case 0, 10, 24 -> BiomeCategories.OCEAN; // ocean, frozenOcean, deepOcean
// PLAINS
case 1 -> BiomeCategories.PLAINS; // plains
// DESERT
case 2, 17 -> BiomeCategories.DESERT; // desert, desertHills
// EXTREME_HILLS (Vanilla mountains)
case 3, 20, 34 -> BiomeCategories.EXTREME_HILLS; // extremeHills, extremeHillsEdge, extremeHillsPlus
// FOREST
case 4, 18, 27, 28, 29 ->
BiomeCategories.FOREST; // forest, forestHills, birchForest, birchForestHills, roofedForest
// TAIGA
case 5, 19, 30, 31, 32, 33 ->
BiomeCategories.TAIGA; // taiga, taigaHills, coldTaiga, coldTaigaHills, megaTaiga, megaTaigaHills
// SWAMP
case 6 -> BiomeCategories.SWAMP; // swampland
// RIVER
case 7, 11 -> BiomeCategories.RIVER; // river, frozenRiver
// NETHER
case 8 -> BiomeCategories.NETHER; // hell
// THE_END
case 9 -> BiomeCategories.THE_END; // sky
// ICY
case 12, 13 -> BiomeCategories.ICY; // icePlains, iceMountains
// MUSHROOM
case 14, 15 -> BiomeCategories.MUSHROOM; // mushroomIsland, mushroomIslandShore
// BEACH
case 16, 25, 26 -> BiomeCategories.BEACH; // beach, stoneBeach, coldBeach
// JUNGLE
case 21, 22, 23 -> BiomeCategories.JUNGLE; // jungle, jungleHills, jungleEdge
// SAVANNA
case 35, 36 -> BiomeCategories.SAVANNA; // savanna, savannaPlateau
// MESA
case 37, 38, 39 -> BiomeCategories.MESA; // mesa, mesaPlateau_F, mesaPlateau
default -> null; // Not a vanilla biome or unknown
};
}
private static final Map<Class<? extends BiomeGenBase>, BiomeCategories> VANILLA_CLASS_MAP = createVanillaClassMap();
private static Map<Class<? extends BiomeGenBase>, BiomeCategories> createVanillaClassMap() {
final Map<Class<? extends BiomeGenBase>, BiomeCategories> map = new HashMap<>();
// Most specific first (subclasses before superclasses)
map.put(BiomeGenStoneBeach.class, BiomeCategories.BEACH);
map.put(BiomeGenBeach.class, BiomeCategories.BEACH);
map.put(BiomeGenMushroomIsland.class, BiomeCategories.MUSHROOM);
map.put(BiomeGenOcean.class, BiomeCategories.OCEAN);
map.put(BiomeGenPlains.class, BiomeCategories.PLAINS);
map.put(BiomeGenDesert.class, BiomeCategories.DESERT);
map.put(BiomeGenHills.class, BiomeCategories.EXTREME_HILLS);
map.put(BiomeGenForest.class, BiomeCategories.FOREST);
map.put(BiomeGenTaiga.class, BiomeCategories.TAIGA);
map.put(BiomeGenSwamp.class, BiomeCategories.SWAMP);
map.put(BiomeGenRiver.class, BiomeCategories.RIVER);
map.put(BiomeGenHell.class, BiomeCategories.NETHER);
map.put(BiomeGenEnd.class, BiomeCategories.THE_END);
map.put(BiomeGenSnow.class, BiomeCategories.ICY);
map.put(BiomeGenJungle.class, BiomeCategories.JUNGLE);
map.put(BiomeGenSavanna.class, BiomeCategories.SAVANNA);
map.put(BiomeGenMesa.class, BiomeCategories.MESA);
return map;
}
private static BiomeCategories detectVanillaBiomeByClass(BiomeGenBase biome) {
// Direct class lookup (O(1) for exact matches)
final BiomeCategories direct = VANILLA_CLASS_MAP.get(biome.getClass());
if (direct != null) {
return direct;
}
// Fallback: instanceof checks for subclasses (modded biomes extending vanilla)
for (Map.Entry<Class<? extends BiomeGenBase>, BiomeCategories> entry : VANILLA_CLASS_MAP.entrySet()) {
if (entry.getKey().isInstance(biome)) {
return entry.getValue();
}
}
return null;
}
private static BiomeCategories detectModdedBiome(BiomeGenBase biome) {
return ModdedBiomeDetector.detectModdedBiome(biome);
}
private static BiomeCategories detectBiomeByName(BiomeGenBase biome) {
if (biome.biomeName == null) return null;
final String name = biome.biomeName.toLowerCase();
// Check for keywords in biome names
// Priority order matters - check more specific terms first
if (name.contains("nether")) return BiomeCategories.NETHER;
if (name.contains("end")) return BiomeCategories.THE_END;
if (name.contains("ocean") || name.contains("sea")) return BiomeCategories.OCEAN;
if (name.contains("river") || name.contains("stream")) return BiomeCategories.RIVER;
if (name.contains("beach") || name.contains("shore") || name.contains("coast")) return BiomeCategories.BEACH;
if (name.contains("mushroom")) return BiomeCategories.MUSHROOM;
if (name.contains("swamp") || name.contains("marsh") || name.contains("bog")) return BiomeCategories.SWAMP;
if (name.contains("jungle")) return BiomeCategories.JUNGLE;
if (name.contains("savanna") || name.contains("savannah")) return BiomeCategories.SAVANNA;
if (name.contains("mesa") || name.contains("badlands")) return BiomeCategories.MESA;
if (name.contains("desert")) return BiomeCategories.DESERT;
// Mountain detection - for modded biomes
if (name.contains("mountain") || name.contains("peak") || name.contains("alpine") ||
name.contains("cliff") || name.contains("crag")) return BiomeCategories.MOUNTAIN;
// Ice/Snow detection
if (name.contains("ice") || name.contains("frozen") || name.contains("snow") ||
name.contains("arctic") || name.contains("tundra") || name.contains("glacier")) return BiomeCategories.ICY;
if (name.contains("taiga") || name.contains("boreal") || name.contains("conifer")) return BiomeCategories.TAIGA;
if (name.contains("forest") || name.contains("wood") || name.contains("grove") ||
name.contains("thicket")) return BiomeCategories.FOREST;
if (name.contains("plain") || name.contains("field") || name.contains("meadow") ||
name.contains("grassland") || name.contains("prairie")) return BiomeCategories.PLAINS;
return null;
}
private static BiomeCategories detectBiomeByProperties(BiomeGenBase biome) {
final float temp = biome.temperature;
final float rain = biome.rainfall;
// Very cold biomes with snow
if (temp <= 0.0F && biome.enableSnow) {
return BiomeCategories.ICY;
}
// Hot, dry biomes
if (temp >= 2.0F && !biome.enableRain) {
return BiomeCategories.DESERT;
}
// Warm, dry biomes (savanna-like)
if (temp >= 1.0F && rain <= 0.1F && !biome.enableRain) {
return BiomeCategories.SAVANNA;
}
// Wet biomes with high rainfall
if (rain >= 0.85F && temp >= 0.5F && temp <= 1.0F) {
return BiomeCategories.SWAMP;
}
// Cold forested biomes
if (temp >= 0.0F && temp <= 0.4F && rain >= 0.4F) {
return BiomeCategories.TAIGA;
}
// Temperate forested biomes
if (temp >= 0.4F && temp <= 0.9F && rain >= 0.5F) {
return BiomeCategories.FOREST;
}
// Default to plains for temperate, moderate biomes
if (temp >= 0.4F && temp <= 1.0F && rain >= 0.3F && rain <= 0.6F) {
return BiomeCategories.PLAINS;
}
return null;
}
}
@@ -20,14 +20,11 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.AbstractTexture;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
import net.minecraft.world.biome.BiomeGenBase;
import org.joml.Math;
import org.joml.Vector2f;
import org.joml.Vector2i;
@@ -53,6 +50,7 @@ public final class CommonUniforms {
ViewportUniforms.addViewportUniforms(uniforms);
WorldTimeUniforms.addWorldTimeUniforms(uniforms);
SystemTimeUniforms.addSystemTimeUniforms(uniforms);
BiomeUniforms.addBiomeUniforms(uniforms);
new CelestialUniforms(directives.getSunPathRotation()).addCelestialUniforms(uniforms);
IrisExclusiveUniforms.addIrisExclusiveUniforms(uniforms);
IdMapUniforms.addIdMapUniforms(updateNotifier, uniforms, idMap, directives.isOldHandLight());
@@ -67,6 +65,7 @@ public final class CommonUniforms {
// Needs to use a LocationalUniformHolder as we need it for the common uniforms
public static void addDynamicUniforms(DynamicUniformHolder uniforms) {
ExternallyManagedUniforms.addExternallyManagedUniforms116(uniforms);
IdMapUniforms.addEntityIdMapUniforms(uniforms);
FogUniforms.addFogUniforms(uniforms);
@@ -113,6 +112,7 @@ public final class CommonUniforms {
uniforms
.uniform1f(ONCE, "darknessFactor", () -> 0.0F) // This is PER_FRAME in modern, it is an effect added by The Warden. We're just setting to 0 because 1.7.10 doesn't have it.
.uniform1f(ONCE, "darknessLightFactor", () -> 0.0F) // Warden darkness current light factor - 1.7.10 doesn't have it so hardcode to 0
.uniform1b(PER_FRAME, "hideGUI", () -> client.gameSettings.hideGUI)
.uniform1i(PER_FRAME, "isEyeInWater", CommonUniforms::isEyeInWater)
.uniform1f(PER_FRAME, "blindness", CommonUniforms::getBlindness)
@@ -137,11 +137,7 @@ public final class CommonUniforms {
.uniform1f(PER_TICK, "rainStrength", CommonUniforms::getRainStrength)
.uniform1f(PER_TICK, "wetness", new SmoothedFloat(directives.getWetnessHalfLife(), directives.getDrynessHalfLife(), CommonUniforms::getRainStrength, updateNotifier))
.uniform3d(PER_FRAME, "skyColor", CommonUniforms::getSkyColor)
.uniform3d(PER_FRAME, "fogColor", GLStateManager::getFogColor)
.uniform1i(PER_TICK, "biome_precipitation", CommonUniforms::getBiomePrecipitation)
.uniform1f(PER_TICK, "rainfall", CommonUniforms::getBiomeRainfall)
.uniform1f(PER_TICK, "temperature", CommonUniforms::getBiomeTemperature);
.uniform3d(PER_FRAME, "fogColor", GLStateManager::getFogColor);
}
private static boolean isOnGround() {
@@ -153,38 +149,7 @@ public final class CommonUniforms {
return (client.thePlayer != null && client.thePlayer.hurtTime > 0);
}
private static BiomeGenBase getBiome() {
return client.theWorld.getBiomeGenForCoords(MathHelper.floor_double(client.thePlayer.posX), MathHelper.floor_double(client.thePlayer.posZ));
}
private static int getBiomePrecipitation() {
if (client.thePlayer == null || client.theWorld == null) {
return 0;
}
BiomeGenBase biome = getBiome();
float temp = biome.getFloatTemperature(MathHelper.floor_double(client.thePlayer.posX), MathHelper.floor_double(client.thePlayer.posY), MathHelper.floor_double(client.thePlayer.posZ));
if (!biome.enableRain && !biome.enableSnow) {
return 0;
} else if (temp > 0.15F) {
return 1;
} else {
return 2;
}
}
private static float getBiomeRainfall() {
if (client.thePlayer == null || client.theWorld == null) return 0.0F;
return getBiome().rainfall;
}
private static float getBiomeTemperature() {
if (client.thePlayer == null || client.theWorld == null) return 0.0F;
return getBiome().temperature;
}
private static boolean isInvisible() {
private static boolean isInvisible() {
return (client.thePlayer != null && client.thePlayer.isInvisible());
}
@@ -12,9 +12,9 @@ public class ExternallyManagedUniforms {
addMat4(uniformHolder, "iris_ModelViewMatrix");
addMat4(uniformHolder, "u_ModelViewProjectionMatrix");
addMat4(uniformHolder, "iris_NormalMatrix");
// Exclusive to pre-1.19
addFloat(uniformHolder, "darknessFactor");
addFloat(uniformHolder, "darknessLightFactor");
// 1.21.6+
uniformHolder.externallyManagedUniform("heavyFog", UniformType.BOOL);
}
public static void addExternallyManagedUniforms116(UniformHolder uniformHolder) {
@@ -1,16 +1,28 @@
package net.coderbot.iris.uniforms;
import com.gtnewhorizons.angelica.compat.mojang.Camera;
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
import net.coderbot.iris.gl.uniform.UniformHolder;
import net.coderbot.iris.gl.uniform.UniformUpdateFrequency;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.effect.EntityLightningBolt;
import org.joml.Math;
import org.joml.Vector3d;
import org.joml.Vector3dc;
import org.joml.Vector4f;
import java.util.List;
public class IrisExclusiveUniforms {
// Reusable vectors to avoid allocations every frame
private static final Vector3d eyePositionCache = new Vector3d();
private static final Vector3d relativeEyePositionCache = new Vector3d();
private static final Vector4f lightningBoltPositionCache = new Vector4f();
private static final Vector4f ZERO_VECTOR_4f = new Vector4f(0, 0, 0, 0);
public static void addIrisExclusiveUniforms(UniformHolder uniforms) {
WorldInfoUniforms.addWorldInfoUniforms(uniforms);
@@ -24,20 +36,10 @@ public class IrisExclusiveUniforms {
uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "maxPlayerAir", IrisExclusiveUniforms::getMaxAir);
uniforms.uniform1b(UniformUpdateFrequency.PER_FRAME, "firstPersonCamera", IrisExclusiveUniforms::isFirstPersonCamera);
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "isSpectator", IrisExclusiveUniforms::isSpectator);
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "isRightHanded", () -> true); // 1.7.10 doesn't support left-handed mode
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "eyePosition", IrisExclusiveUniforms::getEyePosition);
// TODO: Iris Shaders
// Vector4f zero = new Vector4f(0, 0, 0, 0);
// uniforms.uniform4f(UniformUpdateFrequency.PER_TICK, "lightningBoltPosition", () -> {
// if (Minecraft.getMinecraft().theWorld != null) {
// return StreamSupport.stream(Minecraft.getMinecraft().theWorld.entitiesForRendering().spliterator(), false).filter(bolt -> bolt instanceof LightningBolt).findAny().map(bolt -> {
// Vector3d unshiftedCameraPosition = CameraUniforms.getUnshiftedCameraPosition();
// Vec3 vec3 = bolt.getPosition(Minecraft.getMinecraft().getDeltaFrameTime());
// return new Vector4f((float) (vec3.x - unshiftedCameraPosition.x), (float) (vec3.y - unshiftedCameraPosition.y), (float) (vec3.z - unshiftedCameraPosition.z), 1);
// }).orElse(zero);
// } else {
// return zero;
// }
// });
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "relativeEyePosition", IrisExclusiveUniforms::getRelativeEyePosition);
uniforms.uniform4f(UniformUpdateFrequency.PER_TICK, "lightningBoltPosition", IrisExclusiveUniforms::getLightningBoltPosition);
}
private static float getThunderStrength() {
@@ -88,21 +90,40 @@ public class IrisExclusiveUniforms {
private static boolean isFirstPersonCamera() {
// If camera type is not explicitly third-person, assume it's first-person.
return (Minecraft.getMinecraft().gameSettings.thirdPersonView == 1);
return !Camera.INSTANCE.isThirdPerson();
}
private static boolean isSpectator() {
final PlayerControllerMP controller = Minecraft.getMinecraft().playerController;
if(controller == null)
return false;
return controller.currentGameType.getID() == 3;
return GameModeUtil.isSpectator();
}
private static Vector3d getEyePosition() {
// Objects.requireNonNull(Minecraft.getMinecraft().getCameraEntity());
// return new Vector3d(Minecraft.getMinecraft().getCameraEntity().getX(), Minecraft.getMinecraft().getCameraEntity().getEyeY(), Minecraft.getMinecraft().getCameraEntity().getZ());
final EntityLivingBase eye = Minecraft.getMinecraft().renderViewEntity;
return new Vector3d(eye.posX, eye.posY, eye.posZ);
return eyePositionCache.set(eye.posX, eye.posY + eye.getEyeHeight(), eye.posZ);
}
private static Vector3d getRelativeEyePosition() {
final Vector3dc cameraPos = CameraUniforms.getUnshiftedCameraPosition();
final Vector3d eyePos = getEyePosition();
return relativeEyePositionCache.set(eyePos).sub(cameraPos);
}
private static Vector4f getLightningBoltPosition() {
if (Minecraft.getMinecraft().theWorld != null) {
final List<Entity> weatherEffects = Minecraft.getMinecraft().theWorld.weatherEffects;
for (Entity entity : weatherEffects) {
if (entity instanceof EntityLightningBolt bolt) {
final Vector3dc cameraPos = CameraUniforms.getUnshiftedCameraPosition();
return lightningBoltPositionCache.set(
(float)(bolt.posX - cameraPos.x()),
(float)(bolt.posY - cameraPos.y()),
(float)(bolt.posZ - cameraPos.z()),
1.0f
);
}
}
}
return ZERO_VECTOR_4f;
}
public static class WorldInfoUniforms {
@@ -0,0 +1,85 @@
package net.coderbot.iris.uniforms;
import net.minecraft.world.biome.BiomeGenBase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class VanillaBiomeList {
public static class BiomeEntry {
public final BiomeGenBase biome;
public final String name;
public BiomeEntry(BiomeGenBase biome, String name) {
this.biome = biome;
this.name = name;
}
}
private static final List<BiomeEntry> VANILLA_BIOMES = createVanillaBiomeList();
private static List<BiomeEntry> createVanillaBiomeList() {
final List<BiomeEntry> biomes = new ArrayList<>();
// Vanilla biomes from BiomeGenBase static fields (IDs 0-39)
biomes.add(new BiomeEntry(BiomeGenBase.ocean, "OCEAN"));
biomes.add(new BiomeEntry(BiomeGenBase.plains, "PLAINS"));
biomes.add(new BiomeEntry(BiomeGenBase.desert, "DESERT"));
biomes.add(new BiomeEntry(BiomeGenBase.extremeHills, "EXTREME_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.forest, "FOREST"));
biomes.add(new BiomeEntry(BiomeGenBase.taiga, "TAIGA"));
biomes.add(new BiomeEntry(BiomeGenBase.swampland, "SWAMPLAND"));
biomes.add(new BiomeEntry(BiomeGenBase.river, "RIVER"));
biomes.add(new BiomeEntry(BiomeGenBase.hell, "HELL"));
biomes.add(new BiomeEntry(BiomeGenBase.sky, "SKY"));
biomes.add(new BiomeEntry(BiomeGenBase.frozenOcean, "FROZEN_OCEAN"));
biomes.add(new BiomeEntry(BiomeGenBase.frozenRiver, "FROZEN_RIVER"));
biomes.add(new BiomeEntry(BiomeGenBase.icePlains, "ICE_PLAINS"));
biomes.add(new BiomeEntry(BiomeGenBase.iceMountains, "ICE_MOUNTAINS"));
biomes.add(new BiomeEntry(BiomeGenBase.mushroomIsland, "MUSHROOM_ISLAND"));
biomes.add(new BiomeEntry(BiomeGenBase.mushroomIslandShore, "MUSHROOM_ISLAND_SHORE"));
biomes.add(new BiomeEntry(BiomeGenBase.beach, "BEACH"));
biomes.add(new BiomeEntry(BiomeGenBase.desertHills, "DESERT_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.forestHills, "FOREST_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.taigaHills, "TAIGA_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.extremeHillsEdge, "EXTREME_HILLS_EDGE"));
biomes.add(new BiomeEntry(BiomeGenBase.jungle, "JUNGLE"));
biomes.add(new BiomeEntry(BiomeGenBase.jungleHills, "JUNGLE_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.jungleEdge, "JUNGLE_EDGE"));
biomes.add(new BiomeEntry(BiomeGenBase.deepOcean, "DEEP_OCEAN"));
biomes.add(new BiomeEntry(BiomeGenBase.stoneBeach, "STONE_BEACH"));
biomes.add(new BiomeEntry(BiomeGenBase.coldBeach, "COLD_BEACH"));
biomes.add(new BiomeEntry(BiomeGenBase.birchForest, "BIRCH_FOREST"));
biomes.add(new BiomeEntry(BiomeGenBase.birchForestHills, "BIRCH_FOREST_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.roofedForest, "ROOFED_FOREST"));
biomes.add(new BiomeEntry(BiomeGenBase.coldTaiga, "COLD_TAIGA"));
biomes.add(new BiomeEntry(BiomeGenBase.coldTaigaHills, "COLD_TAIGA_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.megaTaiga, "MEGA_TAIGA"));
biomes.add(new BiomeEntry(BiomeGenBase.megaTaigaHills, "MEGA_TAIGA_HILLS"));
biomes.add(new BiomeEntry(BiomeGenBase.extremeHillsPlus, "EXTREME_HILLS_PLUS"));
biomes.add(new BiomeEntry(BiomeGenBase.savanna, "SAVANNA"));
biomes.add(new BiomeEntry(BiomeGenBase.savannaPlateau, "SAVANNA_PLATEAU"));
biomes.add(new BiomeEntry(BiomeGenBase.mesa, "MESA"));
biomes.add(new BiomeEntry(BiomeGenBase.mesaPlateau_F, "MESA_PLATEAU_F"));
biomes.add(new BiomeEntry(BiomeGenBase.mesaPlateau, "MESA_PLATEAU"));
// Modern End biome variants (1.9+) - all map to the single End biome in 1.7.10
// This allows shaders expecting these constants to work
biomes.add(new BiomeEntry(BiomeGenBase.sky, "THE_END"));
biomes.add(new BiomeEntry(BiomeGenBase.sky, "SMALL_END_ISLANDS"));
biomes.add(new BiomeEntry(BiomeGenBase.sky, "END_MIDLANDS"));
biomes.add(new BiomeEntry(BiomeGenBase.sky, "END_HIGHLANDS"));
biomes.add(new BiomeEntry(BiomeGenBase.sky, "END_BARRENS"));
return Collections.unmodifiableList(biomes);
}
/**
* Returns the cached list of all vanilla biomes with their shader-friendly names.
* The list is immutable and created once during class initialization.
*/
public static List<BiomeEntry> getVanillaBiomes() {
return VANILLA_BIOMES;
}
}
@@ -1,51 +0,0 @@
package net.coderbot.iris.vertices;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormatElement;
public class IrisVertexFormats {
public static final VertexFormatElement ENTITY_ELEMENT;
public static final VertexFormatElement MID_TEXTURE_ELEMENT;
public static final VertexFormatElement TANGENT_ELEMENT;
public static final VertexFormatElement MID_BLOCK_ELEMENT;
public static final VertexFormat TERRAIN;
public static final VertexFormat ENTITY;
static {
ENTITY_ELEMENT = new VertexFormatElement(11, VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.GENERIC, 2);
MID_TEXTURE_ELEMENT = new VertexFormatElement(12, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.GENERIC, 2);
TANGENT_ELEMENT = new VertexFormatElement(13, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, 4);
MID_BLOCK_ELEMENT = new VertexFormatElement(14, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, 3);
ImmutableList.Builder<VertexFormatElement> terrainElements = ImmutableList.builder();
ImmutableList.Builder<VertexFormatElement> entityElements = ImmutableList.builder();
terrainElements.add(DefaultVertexFormat.POSITION_ELEMENT); // 12
terrainElements.add(DefaultVertexFormat.COLOR_ELEMENT); // 16
terrainElements.add(DefaultVertexFormat.TEXTURE_ELEMENT); // 24
terrainElements.add(DefaultVertexFormat.LIGHT_ELEMENT); // 28
terrainElements.add(DefaultVertexFormat.NORMAL_ELEMENT); // 31
terrainElements.add(DefaultVertexFormat.PADDING_ELEMENT); // 32
terrainElements.add(ENTITY_ELEMENT); // 36
terrainElements.add(MID_TEXTURE_ELEMENT); // 44
terrainElements.add(TANGENT_ELEMENT); // 48
terrainElements.add(MID_BLOCK_ELEMENT); // 51
terrainElements.add(DefaultVertexFormat.PADDING_ELEMENT); // 52
entityElements.add(DefaultVertexFormat.POSITION_ELEMENT); // 12
entityElements.add(DefaultVertexFormat.COLOR_ELEMENT); // 16
entityElements.add(DefaultVertexFormat.TEXTURE_ELEMENT); // 24
entityElements.add(DefaultVertexFormat.LIGHT_ELEMENT); // 28
entityElements.add(DefaultVertexFormat.NORMAL_ELEMENT); // 31
entityElements.add(DefaultVertexFormat.PADDING_ELEMENT); // 32
entityElements.add(MID_TEXTURE_ELEMENT); // 40
entityElements.add(TANGENT_ELEMENT); // 44
TERRAIN = new VertexFormat(terrainElements.build());
ENTITY = new VertexFormat(entityElements.build());
}
}
@@ -86,3 +86,4 @@ public net.minecraft.block.material.Material field_76240_I # isTranslucent
public net.minecraft.world.biome.BiomeGenBase field_76765_S # enableRain
public net.minecraft.world.biome.BiomeGenBase field_76766_R # enableSnow
public net.minecraft.world.biome.BiomeGenMutated field_150611_aD # baseBiome
@@ -139,11 +139,16 @@ options.angelica.fontconfig=Font Configuration...
options.angelica.fontconfig.title=Font Configuration
options.angelica.fontconfig.currentfonts=Primary font: §e%s§r Fallback font: §b%s
options.angelica.fontconfig.searchprompt=§7§oSearch fonts...
options.angelica.fontconfig.testareaprompt=§7§oTest area...
options.angelica.fontconfig.testareainfo=Enter text below to see how it renders. Use & for formatting.
options.angelica.fontconfig.testareaexample=&d&lHerobrine&r was &7&m&oNOT&r &nhere
options.angelica.fontconfig.disable_custom_font=Disable Custom Font
options.angelica.fontconfig.enable_custom_font=Enable Custom Font
options.angelica.fontconfig.reset_values=Reset Values
options.angelica.fontconfig.font_quality=Custom Font Quality: %s
options.angelica.fontconfig.shadow_offset=Shadow Offset: %s
options.angelica.fontconfig.shadow_copies=Shadow Copies: %s
options.angelica.fontconfig.bold_copies=Bold Copies: %s
options.angelica.fontconfig.glyph_scale=Glyph Scale: %s
options.angelica.fontconfig.glyph_aspect=Glyph Aspect: %s
options.angelica.fontconfig.whitespace_scale=Whitespace Size: %s
@@ -153,7 +158,9 @@ 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.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; turn this down if you see double text.
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.
options.angelica.fontconfig.bold_copies.tooltip=The number of text copies drawn when rendering bold text. Can improve the appearance of bold text with thinner custom fonts.
options.angelica.fontconfig.glyph_scale.tooltip=The scale of each individual glyph. Extreme values might make your game unplayable.
options.angelica.fontconfig.glyph_aspect.tooltip=The aspect ratio of each individual glyph.
options.angelica.fontconfig.whitespace_scale.tooltip=The scaling factor of blank characters like spaces.
@@ -2,6 +2,8 @@ options.button.shader=光影包……
options.chunks=%s 区块
options.entityShadows=实体阴影
options.droppedItems=%s 个物品
options.droppedItems.max=无限制
sodium.option_impact.low=低
sodium.option_impact.medium=中
sodium.option_impact.high=高
@@ -29,6 +31,8 @@ sodium.options.leaves_quality.name=树叶质量
sodium.options.leaves_quality.tooltip=控制树叶的渲染质量。
sodium.options.grass_quality.name=草方块质量
sodium.options.grass_quality.tooltip=控制草方块侧面的质量。
sodium.options.sodium_smooth_lighting.name=Sodium平滑光照
sodium.options.sodium_smooth_lighting.tooltip=如果启用,将调用钠模组的平滑光照,此选项仅在平滑光照启用时生效。
sodium.options.particle_quality.name=粒子效果
sodium.options.particle_quality.tooltip=控制可同时在画面上渲染的最大粒子数量。
sodium.options.smooth_lighting.tooltip=控制方块是否平滑光照和渲染。这会略微增加重新加载区块所需的时间,但不会影响帧率(FPS)。
@@ -38,7 +42,7 @@ sodium.options.entity_distance.tooltip=实体渲染的距离修正乘数。更
sodium.options.entity_shadows.tooltip=如果启用,将在生物和其他实体下方渲染简单的阴影。
sodium.options.vignette.name=晕影
sodium.options.vignette.tooltip=如果启用,将在玩家的画面上显示晕影效果。除非你的显卡像素填充率有限,否则这不太可能对帧率产生影响。
sodium.options.mipmap_levels.tooltip=控制将用于方块模型纹理的MipMap的数量。较高的值可以更好地渲染远处的方块,但可能会对许多纹理动画的性能产生不利影响。
sodium.options.mipmap_levels.tooltip=控制多级纹理的生成等级。较高的等级可以更好地渲染远处的方块,但可能会对许多纹理动画的性能产生不利影响。
sodium.options.use_chunk_multidraw.name=使用区块多重绘制
sodium.options.use_chunk_multidraw.tooltip=多重绘制允许通过更少的绘制请求来进行多区块渲染,在大大减少了渲染世界时的CPU负载的同时也可能提高了GPU利用率。此选项可能会让一些图形驱动程序出现问题,因此如果遇到相关问题,应尝试禁用它。
sodium.options.use_vertex_objects.name=使用顶点数组对象
@@ -61,7 +65,7 @@ sodium.options.cpu_render_ahead_limit.name=CPU 预渲染限制
sodium.options.cpu_render_ahead_limit.tooltip=指定CPU可以在GPU上等待完成渲染的最大帧数。非常低或非常高的值都可能会导致帧率(FPS)不稳定。
sodium.options.cpu_render_ahead_limit.value=%s 帧
sodium.options.allow_direct_memory_access.name=允许直接内存访问
sodium.options.allow_direct_memory_access.tooltip=如果启用,将允许某些关键代码路径使用直接内存访问来提高性能。这通常会大大减少区块和实体渲染的 CPU 开销,但会使诊断某些错误和崩溃变得更加困难。只有您被要求这么做或知道在做什么时,才应该禁用它。
sodium.options.allow_direct_memory_access.tooltip=如果启用,一些关键代码将被允许通过直接读写内存来提高性能。这通常会大大减少区块和实体渲染的CPU开销,但会使诊断某些错误和崩溃变得更加困难。只有您被要求这么做或知道在做什么时,才应该禁用它。
sodium.options.ignore_driver_blacklist.name=忽略驱动程序冲突
sodium.options.ignore_driver_blacklist.tooltip=如果启用,已知的硬件/驱动程序配置不兼容性将被忽略,以允许您启用那些可能导致游戏问题的配置.请勿更改此项除非您确切知道您在做什么.更改此选项后,必须保存、关闭,然后重新打开设置菜单。
sodium.options.enable_memory_tracing.name=启用内存跟踪
@@ -78,10 +82,10 @@ sodium.options.chunk_update_threads.tooltip=指定用于区块构建的线程数
sodium.options.always_defer_chunk_updates.name=始终推迟区块更新
sodium.options.always_defer_chunk_updates.tooltip=如果启用,渲染将永远不会等待区块更新完成,即使它们很重要。这在某些情况下可以极大地提高帧率(FPS),但可能会在游戏时产生明显的视觉滞后。
sodium.options.use_no_error_context.name=使用禁用错误检查的上下文
sodium.options.use_no_error_context.tooltip=如果启用,OpenGL上下文将在禁用错误检查的情况下创建。这可能会略微提高性能,但也会增加游戏崩溃的风险,而不会优雅地处理OpenGL错误。如果遇到无法解释的突然崩溃,则应禁用此选项。
sodium.options.use_no_error_context.tooltip=如果启用,OpenGL日志将不包含详细错误信息。这可能略微提高性能,但也可能因为无法精确处理OpenGL错误而导致游戏崩溃。如遇到不明原因的突然崩溃,则应禁用此选项。
sodium.options.threads.value=%s 线程
sodium.options.use_gl_state_cache.name=使用GL状态缓存
sodium.options.use_gl_state_cache.tooltip=如果启用,OpenGL状态缓存将减少冗余状态更改的次数.这可以提高性能,但也可能导致一些模组出现问题.每次重启游戏时此项将重置.
sodium.options.use_gl_state_cache.name=启用GL状态缓存
sodium.options.use_gl_state_cache.tooltip=如果启用,OpenGL状态缓存将减少冗余状态更改的次数。这可以提高性能,但也可能导致一些模组出现问题。每次重启游戏时此项将重置。
sodium.options.default=默认
sodium.options.buttons.undo=撤销
sodium.options.buttons.apply=应用
@@ -89,7 +93,7 @@ sodium.options.buttons.donate=给JellySquid买杯咖啡!
options.dynamic_fov=动态视场
options.dynamic_fov.tooltip=如果启用,游戏视场将根据玩家速度发生变化.
options.framerate=%s FPS
iris.shaders.toggled=光影包已切换到 %s!
iris.shaders.toggled=光影包已切换为 %s!
iris.shaders.disabled=光影包已禁用!
options.iris.apply=应用
options.iris.refresh=刷新
@@ -122,12 +126,48 @@ options.iris.setToDefault=将选项设为默认值?
options.iris.profile=配置文件
options.iris.profile.custom=自定义
options.iris.shadowDistance=最大阴影距离
options.iris.shadowDistance.sodium_tooltip=最大阴影距离
options.iris.shadowDistance.enabled=更改渲染阴影的最远距离。超出此距离的地形和实体不会投射出阴影。减少阴影渲染距离可以显著提高性能。
options.iris.shadowDistance.disabled=当前光影包已重设阴影渲染距离,无法更改.
options.iris.shadowDistance.disabled=当前光影包已重设阴影渲染距离,无法更改
options.iris.gui.hide=隐藏 GUI
options.iris.gui.show=显示 GUI
options.dynamic_lights=动态光源
options.dynamic_lights.tooltip=启用动态光源. 模式选择: OFF - 关闭, FASTEST - 500ms延迟, FAST - 250ms延迟, FANCY - 无延迟. 如果正在使用光影则此功能被禁用.
options.dynamic_lights.tooltip=启用动态光源,模式选择:OFF-关闭,FASTEST-500ms延迟,FAST-250ms延迟,FANCY-无延迟
options.dynamic_lights_shader_force=强制启用动态光源
options.dynamic_lights_shader_force.tooltip=启用-启用光影时仍显示动态光源;禁用-启用光影时禁用动态光源。
options.angelica.fontconfig=字体配置...
options.angelica.fontconfig.title=字体配置
options.angelica.fontconfig.currentfonts=主字体:§e%s§r 备用字体:§b%s
options.angelica.fontconfig.searchprompt=§7§o搜索字体...
options.angelica.fontconfig.disable_custom_font=禁用自定义字体
options.angelica.fontconfig.enable_custom_font=启用自定义字体
options.angelica.fontconfig.reset_values=恢复默认配置
options.angelica.fontconfig.font_quality=字体渲染质量:%s
options.angelica.fontconfig.shadow_offset=阴影偏移:%s
options.angelica.fontconfig.glyph_scale=字体缩放:%s
options.angelica.fontconfig.glyph_aspect=字体宽高比:%s
options.angelica.fontconfig.whitespace_scale=空白字符大小:%s
options.angelica.fontconfig.glyph_spacing=字符间距:%s
options.angelica.fontconfig.font_aa_strength=字体抗锯齿强度:%s
options.angelica.fontconfig.aamode.aa_none=抗锯齿:关闭
options.angelica.fontconfig.aamode.aa_4x=抗锯齿:4x MSAA
options.angelica.fontconfig.aamode.aa_16x=抗锯齿:16x MSAA
options.angelica.fontconfig.font_quality.tooltip=自定义字体渲染质量,使其不那么像素化,但会牺牲一些性能与内存占用。
options.angelica.fontconfig.shadow_offset.tooltip=字体衬底阴影偏移的距离。同时影响§l粗体§r文本的绘制方式;如果看到重影的文本,请调低此值。
options.angelica.fontconfig.glyph_scale.tooltip=字体大小的缩放比例。极端值可能使游戏难以游玩。
options.angelica.fontconfig.glyph_aspect.tooltip=字体的的宽高比例
options.angelica.fontconfig.whitespace_scale.tooltip=空白字符(如空格)的缩放比例
options.angelica.fontconfig.glyph_spacing.tooltip=字符之间的间距
options.angelica.fontconfig.font_aa_strength.tooltip=抗锯齿所使用的采样间距。过大可能导致字体看起来模糊,过小可能导致锯齿。请根据您的实际情况选择最佳值。
options.angelica.fontconfig.aamode.tooltip=抗锯齿模式。可以显著改善缩放或斜角观看文本的外观和可读性,但会牺牲一些性能。
options.angelica.droppedItemLimit=掉落物渲染数量上限
options.angelica.droppedItemLimit.tooltip=将被渲染的掉落物的最大数量。较小的值可以提高性能。
options.angelica.mobSpawnerRenderDistance=刷怪笼渲染距离
options.angelica.mobSpawnerRenderDistance.tooltip=刷怪笼内旋转实体的渲染距离
options.angelica.itemdisplaylistcount=物品渲染器缓存限制
options.angelica.itemdisplaylistcount.tooltip=优化物品渲染器中的缓存数量上限。较高的值将显著提高性能,但可能导致显存占用增加
options.angelica.sleepbeforeswap=备用FPS限制器
options.angelica.sleepbeforeswap.tooltip=切换到备用FPS限制器,可以降低帧波动,但会略微增加延迟。最多只会造成一帧的延迟,且在较高帧率下影响较小。
pack.iris.select.title=选择
pack.iris.configure.title=配置
label.iris.true=开启
@@ -1,5 +1,6 @@
package com.gtnewhorizons.angelica.mixins.early.angelica;
import com.gtnewhorizons.angelica.compat.mojang.Camera;
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
import com.gtnewhorizons.angelica.rendering.RenderingState;
import net.minecraft.client.Minecraft;
@@ -19,15 +20,18 @@ public abstract class MixinEntityRenderer implements EntityRendererAccessor {
@Invoker
public abstract float invokeGetNightVisionBrightness(EntityPlayer entityPlayer, float partialTicks);
@Inject(method = "setupCameraTransform", at = @At(value = "TAIL"))
private void angelica$captureCameraMatrix(float partialTicks, int startTime, CallbackInfo ci) {
@Inject(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ActiveRenderInfo;updateRenderInfo(Lnet/minecraft/entity/player/EntityPlayer;Z)V", shift = At.Shift.AFTER))
private void angelica$captureCameraMatrix(float partialTicks, long finishTimeNano, CallbackInfo ci) {
final Minecraft mc = Minecraft.getMinecraft();
final EntityLivingBase viewEntity = mc.renderViewEntity;
Camera.INSTANCE.update(viewEntity, partialTicks);
// Set RenderingState to use the correct camera position
RenderingState.INSTANCE.setCameraPosition(
viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * partialTicks,
viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * partialTicks,
viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * partialTicks
Camera.INSTANCE.getPos().x,
Camera.INSTANCE.getPos().y,
Camera.INSTANCE.getPos().z
);
}
@@ -1,16 +1,10 @@
package com.gtnewhorizons.angelica.mixins.early.angelica.animation;
import com.gtnewhorizons.angelica.utils.AnimationsRenderUtils;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.util.IIcon;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.fluids.RenderBlockFluid;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -18,26 +12,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = RenderBlockFluid.class, remap = false)
public abstract class MixinRenderBlockFluid {
@Unique
private IBlockAccess currentBlockAccess;
@Inject(method = "renderWorldBlock", at = @At(value = "HEAD"))
private void angelica$saveCurrentBlockAccess(IBlockAccess world, int x, int y, int z, Block block, int modelId,
RenderBlocks renderer, CallbackInfoReturnable<Boolean> cir) {
currentBlockAccess = world;
}
/**
* @author laetansky
* @reason mark texture for update
*/
@Overwrite
private IIcon getIcon(IIcon icon) {
if (icon != null) {
AnimationsRenderUtils.markBlockTextureForUpdate(icon, currentBlockAccess);
return icon;
}
return ((TextureMap) Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture))
.getAtlasSprite("missingno");
@Inject(method = "getIcon", at = @At(value = "RETURN", ordinal = 0))
private void angelica$updateTexture(IIcon icon, CallbackInfoReturnable<IIcon> cir) {
AnimationsRenderUtils.markBlockTextureForUpdate(icon, Minecraft.getMinecraft().theWorld);
}
}
@@ -17,19 +17,16 @@ public class MixinRenderGlobal_ItemRenderDist {
@Unique private static final int[] sodium$entityItemCount = new int[256];
@Unique private static int sodium$itemRenderDist = 255;
@Unique private static int sodium$itemRenderedCount;
@Unique private static int sodium$itemLimit = Integer.MAX_VALUE;
@Inject(method = "renderEntities", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/RenderGlobal;countEntitiesRendered:I", ordinal = 0))
private void sodium$resetEntitycount(CallbackInfo ci) {
sodium$itemRenderedCount = 0;
int entityCount = 0;
boolean reachedLimit = false;
sodium$itemLimit = AngelicaConfig.droppedItemLimit == 2048 ? Integer.MAX_VALUE : AngelicaConfig.droppedItemLimit;
final int itemLimit = AngelicaConfig.droppedItemLimit == 2048 ? Integer.MAX_VALUE : AngelicaConfig.droppedItemLimit;
for (int i = 0; i < sodium$entityItemCount.length; i++) {
entityCount += sodium$entityItemCount[i];
sodium$entityItemCount[i] = 0;
if (!reachedLimit && entityCount > sodium$itemLimit) {
if (!reachedLimit && entityCount > itemLimit) {
reachedLimit = true;
sodium$itemRenderDist = i == 0 ? 1 : i;
}
@@ -48,9 +45,7 @@ public class MixinRenderGlobal_ItemRenderDist {
if (flag && entity instanceof EntityItem) {
final int i = Math.min((int) (entity.getDistanceSq(d0, d1, d2) / 4.0D), 255);
sodium$entityItemCount[i]++;
final boolean doRender = i <= sodium$itemRenderDist && sodium$itemRenderedCount < sodium$itemLimit;
if (doRender) sodium$itemRenderedCount++;
return doRender;
return i <= sodium$itemRenderDist;
}
return flag;
}
@@ -49,8 +49,7 @@ public abstract class MixinEntityRenderer implements IResourceManagerReloadListe
@Inject(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/ForgeHooksClient;dispatchRenderLast(Lnet/minecraft/client/renderer/RenderGlobal;F)V", remap = false))
private void iris$endLevelRender(float partialTicks, long limitTime, CallbackInfo callback, @Share("pipeline") LocalRef<WorldRenderingPipeline> pipeline) {
// TODO: Iris
final Camera camera = new Camera(mc.renderViewEntity, partialTicks);
HandRenderer.INSTANCE.renderTranslucent(partialTicks, camera, mc.renderGlobal, pipeline.get());
HandRenderer.INSTANCE.renderTranslucent(partialTicks, Camera.INSTANCE, mc.renderGlobal, pipeline.get());
Minecraft.getMinecraft().mcProfiler.endStartSection("iris_final");
pipeline.get().finalizeLevelRendering();
pipeline.set(null);
@@ -67,8 +66,7 @@ public abstract class MixinEntityRenderer implements IResourceManagerReloadListe
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;clipRenderersByFrustum(Lnet/minecraft/client/renderer/culling/ICamera;F)V", shift = At.Shift.AFTER), method = "renderWorld(FJ)V")
private void iris$beginEntities(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef<WorldRenderingPipeline> pipeline) {
final Camera camera = new Camera(mc.renderViewEntity, partialTicks);
pipeline.get().renderShadows((EntityRenderer) (Object) this, camera);
pipeline.get().renderShadows((EntityRenderer) (Object) this, Camera.INSTANCE);
}
@@ -1,5 +1,6 @@
package com.gtnewhorizons.angelica.mixins.early.sodium;
import com.gtnewhorizons.angelica.compat.iris.BiomeCategoryCache;
import com.gtnewhorizons.angelica.utils.EventUtils;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraftforge.event.terraingen.BiomeEvent;
@@ -9,9 +10,11 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(BiomeGenBase.class)
public class MixinBiomeGenBase {
private final ThreadLocal<BiomeEvent.GetWaterColor> waterColorEventLocal = ThreadLocal.withInitial(() -> new BiomeEvent.GetWaterColor((BiomeGenBase)(Object)this, 0));;
private final ThreadLocal<BiomeEvent.GetGrassColor> grassColorEventLocal = ThreadLocal.withInitial(() -> new BiomeEvent.GetGrassColor((BiomeGenBase)(Object)this, 0));;
public class MixinBiomeGenBase implements BiomeCategoryCache {
@Unique
private int cachedBiomeCategory = -1;
private final ThreadLocal<BiomeEvent.GetWaterColor> waterColorEventLocal = ThreadLocal.withInitial(() -> new BiomeEvent.GetWaterColor((BiomeGenBase)(Object)this, 0));
private final ThreadLocal<BiomeEvent.GetGrassColor> grassColorEventLocal = ThreadLocal.withInitial(() -> new BiomeEvent.GetGrassColor((BiomeGenBase)(Object)this, 0));
private final ThreadLocal<BiomeEvent.GetFoliageColor> foliageColorEventLocal = ThreadLocal.withInitial(() -> new BiomeEvent.GetFoliageColor((BiomeGenBase)(Object)this, 0));
@Unique
@@ -41,4 +44,14 @@ public class MixinBiomeGenBase {
prepareEvent(event, original);
return event;
}
@Override
public int iris$getCachedCategory() {
return cachedBiomeCategory;
}
@Override
public void iris$setCachedCategory(int category) {
this.cachedBiomeCategory = category;
}
}
@@ -1,6 +1,7 @@
package com.gtnewhorizons.angelica.mixins.early.sodium;
import com.gtnewhorizons.angelica.compat.mojang.Camera;
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
import com.gtnewhorizons.angelica.compat.toremove.MatrixStack;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt;
@@ -20,7 +21,6 @@ import net.coderbot.iris.pipeline.WorldRenderingPhase;
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
import net.coderbot.iris.uniforms.CapturedRenderingState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.RenderHelper;
@@ -162,10 +162,8 @@ public class MixinRenderGlobal implements IRenderGlobalExt {
if(pass == 0) {
pipeline.setPhase(WorldRenderingPhase.TERRAIN_CUTOUT);
} else if(pass == 1) {
final Camera camera = new Camera(mc.renderViewEntity, (float) partialTicks);
if (!ShadowRenderer.ACTIVE) {
iris$beginTranslucents(pipeline, camera);
iris$beginTranslucents(pipeline, Camera.INSTANCE);
}
pipeline.setPhase(WorldRenderingPhase.TERRAIN_TRANSLUCENT);
@@ -204,10 +202,7 @@ public class MixinRenderGlobal implements IRenderGlobalExt {
}
private boolean isSpectatorMode() {
final PlayerControllerMP controller = Minecraft.getMinecraft().playerController;
if(controller == null)
return false;
return controller.currentGameType.getID() == 3;
return GameModeUtil.isSpectator();
}
/**
@@ -222,11 +217,10 @@ public class MixinRenderGlobal implements IRenderGlobalExt {
final Frustrum frustum = (Frustrum) frustrum;
boolean hasForcedFrustum = false;
boolean spectator = isSpectatorMode();
Camera camera = new Camera(mc.renderViewEntity, partialTicks);
frustum.setPosition(camera.getPos().x, camera.getPos().y, camera.getPos().z);
frustum.setPosition(Camera.INSTANCE.getPos().x, Camera.INSTANCE.getPos().y, Camera.INSTANCE.getPos().z);
try {
this.renderer.updateChunks(camera, frustum, hasForcedFrustum, sodium$frame++, spectator);
this.renderer.updateChunks(Camera.INSTANCE, frustum, hasForcedFrustum, sodium$frame++, spectator);
} finally {
RenderDevice.exitManagedCode();
}