Compare commits

...
Author SHA1 Message Date
Caedis e6039691b5 Remove forced even unicode gui scaling (#840) 2025-01-15 14:39:21 -06:00
paulzzh 5db1edba33 fix MC-76356 Bold unicode characters appear doubled (#834) 2025-01-05 15:24:16 +00:00
Martin Robertz d450461726 update bs + deps (#823) 2025-01-04 13:50:46 -08:00
embeddedt 95f8afc0f3 Remove use of empty build tasks, submit empty data directly to result queue (#821) 2024-12-27 21:39:05 -08:00
Caedis 19635e20ec Disable optimizeInWorldItemRendering by default for now (#820) 2024-12-25 23:25:42 -06:00
BucketBrigade ead4e11376 Expose texture updates to API (#805)
* Expose texture updates to API

* Expose for blocks as well

* Fix mistake

* Fixed API
2024-12-19 19:04:24 -08:00
FM Bellomy b0ceb5306a the most boring typo PR of all time (#810) 2024-12-19 13:25:56 -08:00
embeddedt 99a81369f0 fix origin weirdness (#799) 2024-12-17 10:09:22 -08:00
nshepperd e2ee822948 Only clear the translucency sorting render queue when we're not rendering shadows. (#798) 2024-12-16 13:30:20 -08:00
nshepperd 9fe7e800f6 Remove broken reflection in ChunkBufferSorter. (#797) 2024-12-16 21:11:05 +00:00
embeddedt debfcdfda0 Properly prevent block face culling when TS is active (#796) 2024-12-16 13:07:00 -08:00
embeddedt df662188f4 Fix terrain rendering incorrectly when far from origin (#790) 2024-12-13 18:14:00 +00:00
embeddedt 842916405f Fix rebuild check being wrong when shaders are on (#788) 2024-12-13 16:55:58 +00:00
embeddedt 09afe81290 Fix chunk render manager state not swapping, causing lower render distance with shaders on 2024-12-13 08:52:32 -08:00
Caedis 292809d8e8 Actually fix xaero's crosshair (#781) 2024-12-11 21:50:04 +00:00
Caedis 47503ce254 Fix invisible crosshair with Xaero's Minimap (#775) 2024-12-11 16:32:49 -05:00
ah-OOG-ah f738adbdef Frametime exploration (#742)
* Sleep before swap

* Add a config

* I think this is slightly less jittery
2024-12-06 09:09:26 -08:00
Alexdoru 70d15f2383 Set render distance for mob inside mod spawner to 16 blocks (#761)
* set render distance for mob inside mod spawner to 16 blocks

* add config in angelica

* add slider in video setting menu
2024-12-02 15:20:44 -10:00
kurrycatandDarren Eberly d66b5577f4 add missing GL calls in GLStateManager (#767)
Co-authored-by: Darren Eberly <[email protected]>
2024-12-02 09:12:44 -05:00
ah-OOG-ah e293f12fb8 Refresh Notfine options on world load (#760) 2024-12-01 00:03:21 +00:00
kurrycat b69eca6749 add missing Pipeline::syncProgram for glCallList (#762) 2024-11-30 10:38:00 -10:00
Jason Mitchell 03342f08c6 Update README.MD 2024-11-27 09:03:01 -08:00
ah-OOG-ah b85614f983 Null check (#756) 2024-11-26 22:19:05 +00:00
24 changed files with 284 additions and 131 deletions

No files matched your search

+4 -4
View File
@@ -8,19 +8,19 @@
* It's the angel that pulls you out of OptiFine's hell -Roadhog360
## **Beta Quality - Here there be Dragons**
* Shaders sneak preview - Please don't report issues yet, but please do submit fixes
* Shaders - Beta
* Complementary & BSL mostly function, but have some bugs
* Sildurs, Seus, and any other shader probably doesn't work
# Required Dependencies
* [UniMixins](https://github.com/LegacyModdingMC/UniMixins/releases) >= 0.1.14
* [GTNHLib](https://github.com/GTNewHorizons/GTNHLib/releases) >= 0.4.2
* [UniMixins](https://github.com/LegacyModdingMC/UniMixins/releases) >= 0.1.19
* [GTNHLib](https://github.com/GTNewHorizons/GTNHLib/releases) >= 0.5.20
* NOTE: Some mods are not required, but a specific version is required if present - see: `Permanent Incompatibilities` below.
# Known (temporary) Incompatibilities
* Forge Relocation - Currently non Thread Safe; safe if not in use
* ProjectRed Frames - Currently non Thread Safe; safe if not in use'
* ProjectRed Frames - Currently non Thread Safe; safe if not in use
# Potential Incompatibilities
* EndlessIDs - Compat commits have been made, might work, might not - not fully tested
+8 -8
View File
@@ -49,7 +49,7 @@ configurations {
}
dependencies {
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.5.78")
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.6.9")
compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:0.4.0") { transitive = false }
@@ -57,11 +57,11 @@ dependencies {
annotationProcessor("org.projectlombok:lombok:1.18.22")
// Use modern models+textures to inject QuadProviders
devOnlyNonPublishable('com.github.GTNewHorizons:TX-Loader:1.7.2:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:TX-Loader:1.8.0:dev')
// Iris Shaders
compileOnly('org.jetbrains:annotations:24.0.1')
api("com.github.GTNewHorizons:GTNHLib:0.5.20:dev")
api("com.github.GTNewHorizons:GTNHLib:0.6.0: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
@@ -70,18 +70,18 @@ dependencies {
compileOnly "org.apache.ant:ant:1.8.2"
// Because who doesn't want NEI
devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.6.45-GTNH:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:CodeChickenCore:1.3.10:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.7.4-GTNH:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:CodeChickenCore:1.4.0:dev')
// Notfine Deps
compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev")
devOnlyNonPublishable("com.github.GTNewHorizons:Baubles:1.0.4:dev")
compileOnly("com.github.GTNewHorizons:twilightforest:2.6.35:dev") { transitive = false }
compileOnly("com.github.GTNewHorizons:twilightforest:2.7.1:dev") { transitive = false }
compileOnly(rfg.deobf('curse.maven:witchery-69673:2234410'))
compileOnly("com.github.GTNewHorizons:TinkersConstruct:1.12.14-GTNH:dev") { transitive = false }
compileOnly("com.github.GTNewHorizons:TinkersConstruct:1.13.1-GTNH:dev") { transitive = false }
compileOnly("com.github.GTNewHorizons:Natura:2.7.5:dev")
compileOnly("com.github.GTNewHorizons:ThaumicHorizons:1.6.4:dev")
compileOnly("com.github.GTNewHorizons:ThaumicHorizons:1.6.5:dev")
compileOnly("com.github.GTNewHorizons:Battlegear2:1.4.1:dev") { transitive = false }
compileOnly(rfg.deobf('maven.modrinth:backhand:1.4.1')) { transitive = false }
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+1 -1
View File
@@ -16,5 +16,5 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.29'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.30'
}
@@ -0,0 +1,27 @@
package com.gtnewhorizons.angelica.api;
import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite;
import com.gtnewhorizons.angelica.mixins.interfaces.ITexturesCache;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.util.IIcon;
/**
* Exposes a method to the API that allow mods to add texture update compat
*/
@SuppressWarnings("unused")
public class TextureServices {
@SuppressWarnings("unused")
public static void updateBlockTextureAnimation(IIcon icon, RenderBlocks renderBlocks) {
if (renderBlocks instanceof ITexturesCache texturesCache) {
texturesCache.getRenderedTextures().add(icon);
}
}
@SuppressWarnings("unused")
public static void updateTextureAnimation(IIcon icon) {
if(icon instanceof IPatchedTextureAtlasSprite patchedSprite) {
patchedSprite.markNeedsAnimationUpdate();
}
}
}
@@ -437,8 +437,6 @@ public class BatchingFontRenderer {
chr = MCFONT_CHARS.charAt(lutIndex);
}
final float shadowOffset = unicodeFlag ? 0.5F : 1.0F;
// Check ASCII space, NBSP, NNBSP
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
curX += 4;
@@ -452,6 +450,7 @@ public class BatchingFontRenderer {
final float uSz;
final float vSz;
final float itOff = curItalic ? 1.0F : 0.0F; // italic offset
final float shadowOffset;
final ResourceLocation texture;
if (lutIndex == -1 || unicodeFlag) {
@@ -459,6 +458,7 @@ public class BatchingFontRenderer {
continue;
}
// Draw unicode char
shadowOffset = 0.5F;
final int uniPage = chr / 256;
texture = getUnicodePageLocation(uniPage);
final int startColumn = this.glyphWidth[chr] >>> 4;
@@ -475,6 +475,7 @@ public class BatchingFontRenderer {
} else {
// Draw "ASCII" char
shadowOffset = 1.0F;
uStart = ((lutIndex % 16) * 8) / 128.0F;
vStart = (float) ((lutIndex / 16) * 8) / 128.0F;
xAdvance = this.charWidth[lutIndex];
@@ -138,14 +138,27 @@ public class AngelicaConfig {
@Config.RequiresMcRestart
public static boolean enableZoom;
@Config.Comment("Optimizes in-world item rendering")
@Config.DefaultBoolean(true)
@Config.Comment("Optimizes in-world item rendering [Experimental]")
@Config.DefaultBoolean(false)
@Config.RequiresMcRestart
public static boolean optimizeInWorldItemRendering;
public static boolean optimizeInWorldItemRendering_WIP;
@Config.Comment("Max amount of display lists to cache for optimized item rendering. Higher number will use more VRAM")
@Config.DefaultInt(256)
@Config.RangeInt(min = 64, max = 1024)
public static int itemRendererDisplayListCacheSize;
@Config.Comment("Render distance for the spinning mob inside mod spawners")
@Config.DefaultDouble(16D)
@Config.RangeDouble(min = 16D, max = 64D)
public static double mobSpawnerRenderDistance;
@Config.Comment("Switches to an alternate FPS limiter that gives more stable frametimes, in exchange for slightly " +
"more latency. Will never introduce more than one frame of latency, and has a lower impact at higher framerates.")
@Config.DefaultBoolean(false)
public static boolean sleepBeforeSwap;
@Config.Comment("Allows unicode languages to use an odd gui scale")
@Config.DefaultBoolean(true)
public static boolean removeUnicodeEvenScaling;
}
@@ -69,6 +69,7 @@ import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
@@ -960,32 +961,52 @@ public class GLStateManager {
glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, j);
}
public static void glDrawArrays(int mode, int first, int count) {
// Iris -- TODO: This doesn't seem to work and is related to matchPass()
if(AngelicaConfig.enableIris) {
Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram);
}
GL11.glDrawArrays(mode, first, count);
}
public static void glDrawBuffer(int mode) {
GL11.glDrawBuffer(mode);
}
public static void glDrawElements(int mode, IntBuffer indices) {
if(AngelicaConfig.enableIris) {
Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram);
}
GL11.glDrawElements(mode, indices);
}
public static void glBegin(int mode) {
public static void trySyncProgram() {
if (AngelicaConfig.enableIris) {
Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram);
}
}
public static void glBegin(int mode) {
trySyncProgram();
GL11.glBegin(mode);
}
public static void glDrawElements(int mode, ByteBuffer indices) {
trySyncProgram();
GL11.glDrawElements(mode, indices);
}
public static void glDrawElements(int mode, IntBuffer indices) {
trySyncProgram();
GL11.glDrawElements(mode, indices);
}
public static void glDrawElements(int mode, ShortBuffer indices) {
trySyncProgram();
GL11.glDrawElements(mode, indices);
}
public static void glDrawElements(int mode, int indices_count, int type, long indices_buffer_offset) {
trySyncProgram();
GL11.glDrawElements(mode, indices_count, type, indices_buffer_offset);
}
public static void glDrawElements(int mode, int count, int type, ByteBuffer indices) {
trySyncProgram();
GL11.glDrawElements(mode, count, type, indices);
}
public static void glDrawBuffer(int mode) {
trySyncProgram();
GL11.glDrawBuffer(mode);
}
public static void glDrawArrays(int mode, int first, int count) {
trySyncProgram();
GL11.glDrawArrays(mode, first, count);
}
public static void glLogicOp(int opcode) {
GL11.glLogicOp(opcode);
}
@@ -1240,6 +1261,7 @@ public class GLStateManager {
if(list < 0) {
VBOManager.get(list).render();
} else {
trySyncProgram();
GL11.glCallList(list);
if(glListChanges.containsKey(list)) {
for(Map.Entry<IStateStack<?>, ISettableState<?>> entry : glListChanges.get(list)) {
@@ -136,6 +136,10 @@ public class HUDCaching {
guiForge.callRenderPortal(width, height, partialTicks);
}
if (renderCrosshairsCaptured) {
if (ModStatus.isXaerosMinimapLoaded){
// this fixes the crosshair going invisible when no lines are being drawn under the minimap
GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
}
guiForge.callRenderCrosshairs(width, height);
}
if (ModStatus.isThaumcraftLoaded || ModStatus.isThaumicHorizonsLoaded){
@@ -80,7 +80,7 @@ public enum Mixins {
ANGELICA_ITEM_DISPLAY_LIST_OPTIMIZATION(new Builder("Optimized item rendering by wrapping them with display lists")
.setPhase(Phase.EARLY).addMixinClasses("angelica.itemrenderer.MixinItemRenderer").setSide(Side.CLIENT)
.setApplyIf(() -> AngelicaConfig.optimizeInWorldItemRendering)
.setApplyIf(() -> AngelicaConfig.optimizeInWorldItemRendering_WIP)
.addTargetedMod(TargetedMod.VANILLA)),
// Not compatible with the lwjgl debug callbacks, so disable if that's enabled
@@ -137,6 +137,7 @@ public enum Mixins {
,"sodium.MixinRenderGlobal"
,"sodium.MixinWorldClient"
,"sodium.MixinTileEntity"
,"sodium.MixinTileEntityMobSpawner"
,"sodium.MixinEffectRenderer"
,"sodium.MixinTileEntityRendererDispatcher"
,"sodium.MixinLongHashMap"
@@ -218,6 +219,11 @@ public enum Mixins {
"angelica.animation.MixinWorldRenderer",
"angelica.animation.MixinRenderItem")),
SCALED_RESOUTION_UNICODE_FIX(new Builder("Removes unicode languages gui scaling being forced to even values").setPhase(Phase.EARLY)
.setSide(Side.CLIENT).addTargetedMod(TargetedMod.VANILLA)
.setApplyIf(() -> AngelicaConfig.removeUnicodeEvenScaling)
.addMixinClasses("angelica.bugfixes.MixinScaledResolution_UnicodeFix")),
EXTRA_UTILITIES_THREAD_SAFETY(new Builder("Enable thread safety fixes in Extra Utilities").setPhase(Phase.LATE)
.addTargetedMod(TargetedMod.EXTRAUTILS).setSide(Side.CLIENT)
.setApplyIf(() -> CompatConfig.fixExtraUtils)
@@ -1,19 +1,23 @@
package jss.notfine.proxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import jss.notfine.config.NotFineConfig;
import jss.notfine.core.Settings;
import jss.notfine.core.SettingsManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
public class ClientProxy extends CommonProxy {
@Override
public void preInit(FMLPreInitializationEvent event) {
FMLCommonHandler.instance().bus().register(this);
MinecraftForge.EVENT_BUS.register(this);
if(!NotFineConfig.allowAdvancedOpenGL) {
Minecraft.getMinecraft().gameSettings.advancedOpengl = false;
}
@@ -29,12 +33,13 @@ public class ClientProxy extends CommonProxy {
}
}
@Override
public void init(FMLInitializationEvent event) { }
@Override
public void postInit(FMLPostInitializationEvent event) {
SettingsManager.settingsFile.loadSettings();
}
@SubscribeEvent
public void worldLoad(WorldEvent.Load event) {
SettingsManager.graphicsUpdated();
}
}
@@ -127,6 +127,15 @@ public class SodiumGameOptionPages {
}
}, (opts) -> opts.fullScreen)
.build())
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
.setName(I18n.format("options.angelica.sleepbeforeswap"))
.setTooltip(I18n.format("options.angelica.sleepbeforeswap.tooltip"))
.setControl(TickBoxControl::new)
.setBinding((opts, value) -> {
AngelicaConfig.sleepBeforeSwap = value;
}, opts -> AngelicaConfig.sleepBeforeSwap)
.setImpact(OptionImpact.VARIES)
.build())
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
.setName(I18n.format("options.vsync"))
.setTooltip(I18n.format("sodium.options.v_sync.tooltip"))
@@ -164,6 +173,15 @@ public class SodiumGameOptionPages {
.setImpact(OptionImpact.MEDIUM)
.build()
)
.add(
OptionImpl.createBuilder(int.class, angelicaOpts)
.setName(I18n.format("options.angelica.mobSpawnerRenderDistance"))
.setTooltip(I18n.format("options.angelica.mobSpawnerRenderDistance.tooltip"))
.setControl(option -> new SliderControl(option, 16, 64, 1, ControlValueFormatter.number()))
.setBinding((options, value) -> AngelicaConfig.mobSpawnerRenderDistance = value, options -> (int) AngelicaConfig.mobSpawnerRenderDistance)
.setImpact(OptionImpact.MEDIUM)
.build()
)
.build());
return new OptionPage(I18n.format("stat.generalButton"), ImmutableList.copyOf(groups));
@@ -178,8 +196,10 @@ public class SodiumGameOptionPages {
.setTooltip(I18n.format("sodium.options.graphics_quality.tooltip"))
.setControl(option -> new CyclingControl<>(option, GraphicsMode.class))
.setBinding(
(opts, value) -> { opts.fancyGraphics = value.isFancy();
SettingsManager.graphicsUpdated(); },
(opts, value) -> {
opts.fancyGraphics = value.isFancy();
SettingsManager.graphicsUpdated();
},
opts -> GraphicsMode.fromBoolean(opts.fancyGraphics))
.setImpact(OptionImpact.HIGH)
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
@@ -35,6 +35,7 @@ import me.jellysquid.mods.sodium.client.world.ChunkStatusListener;
import me.jellysquid.mods.sodium.common.util.IdTable;
import me.jellysquid.mods.sodium.common.util.collections.FutureDequeDrain;
import net.coderbot.iris.shadows.ShadowRenderingState;
import net.coderbot.iris.sodium.shadow_map.SwappableChunkRenderManager;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.tileentity.TileEntity;
@@ -47,7 +48,7 @@ import java.util.Collection;
import java.util.Deque;
import java.util.concurrent.CompletableFuture;
public class ChunkRenderManager<T extends ChunkGraphicsState> implements ChunkStatusListener {
public class ChunkRenderManager<T extends ChunkGraphicsState> implements ChunkStatusListener, SwappableChunkRenderManager {
/**
* The maximum distance a chunk can be from the player's camera in order to be eligible for blocking updates.
*/
@@ -249,7 +250,11 @@ public class ChunkRenderManager<T extends ChunkGraphicsState> implements ChunkSt
}
private void addChunk(ChunkRenderContainer<T> render) {
final boolean canRebuild = AngelicaConfig.enableIris ? !ShadowRenderingState.areShadowsCurrentlyBeingRendered() : render.canRebuild();
boolean canRebuild = render.canRebuild();
if (AngelicaConfig.enableIris && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
canRebuild = false;
}
if (render.needsRebuild() && canRebuild) {
if (!this.alwaysDeferChunkUpdates && render.needsImportantRebuild()) {
@@ -366,9 +371,7 @@ public class ChunkRenderManager<T extends ChunkGraphicsState> implements ChunkSt
private void reset() {
if(!AngelicaConfig.enableIris || !ShadowRenderingState.areShadowsCurrentlyBeingRendered()) this.rebuildQueue.clear();
if(!AngelicaConfig.enableIris || !ShadowRenderingState.areShadowsCurrentlyBeingRendered()) this.importantRebuildQueue.clear();
this.sortQueue.clear();
if(!AngelicaConfig.enableIris || !ShadowRenderingState.areShadowsCurrentlyBeingRendered()) this.sortQueue.clear();
this.visibleTileEntities.clear();
@@ -549,25 +552,39 @@ public class ChunkRenderManager<T extends ChunkGraphicsState> implements ChunkSt
continue;
}
// Do not allow distant chunks to block rendering
if (this.alwaysDeferChunkUpdates || !this.isChunkPrioritized(render)) {
this.builder.deferRebuild(render);
} else {
futures.add(this.builder.scheduleRebuildTaskAsync(render));
}
CompletableFuture<ChunkBuildResult<T>> futureTask = this.builder.scheduleRebuildTaskAsync(render);
this.dirty = true;
submitted++;
// Limit quantity of updates submitted if we are deferring all important builds
if (this.alwaysDeferChunkUpdates && submitted >= budget)
break;
if (futureTask != null) {
this.dirty = true;
// Do not allow distant chunks to block rendering
if (this.alwaysDeferChunkUpdates || !this.isChunkPrioritized(render)) {
this.builder.handleCompletion(futureTask);
} else {
futures.add(futureTask);
}
submitted++;
// Limit quantity of updates submitted if we are deferring all important builds
if (this.alwaysDeferChunkUpdates && submitted >= budget)
break;
} else {
// Immediately submit empty data to the queue and do not count this against the budget
this.builder.enqueueUpload(new ChunkBuildResult<>(render, ChunkRenderData.EMPTY));
}
}
while (submitted < budget && !this.rebuildQueue.isEmpty()) {
ChunkRenderContainer<T> render = this.rebuildQueue.dequeue();
this.builder.deferRebuild(render);
submitted++;
CompletableFuture<ChunkBuildResult<T>> futureTask = this.builder.scheduleRebuildTaskAsync(render);
if(futureTask != null) {
this.builder.handleCompletion(futureTask);
submitted++;
} else {
// Immediately submit empty data to the queue and do not count this against the budget
this.builder.enqueueUpload(new ChunkBuildResult<>(render, ChunkRenderData.EMPTY));
}
}
// always do at least one sort
@@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.ints.IntArrays;
import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType;
import me.jellysquid.mods.sodium.client.render.chunk.format.hfp.HFPModelVertexType;
import me.jellysquid.mods.sodium.client.render.chunk.format.sfp.SFPModelVertexType;
import net.coderbot.iris.sodium.vertex_format.terrain_xhfp.XHFPModelVertexType;
import java.nio.Buffer;
import java.nio.ByteBuffer;
@@ -14,22 +15,10 @@ import java.util.BitSet;
public class ChunkBufferSorter {
private static final Class<?> OCULUS_VERTEX_TYPE;
static {
Class<?> clz;
try {
clz = Class.forName("net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType");
} catch(Throwable e) {
clz = null;
}
OCULUS_VERTEX_TYPE = clz;
}
public static void sortStandardFormat(ChunkVertexType vertexType, ByteBuffer buffer, int bufferLen, float x, float y, float z) {
boolean isCompact;
if(vertexType.getClass() == HFPModelVertexType.class || vertexType.getClass() == OCULUS_VERTEX_TYPE) {
if(vertexType.getClass() == HFPModelVertexType.class || vertexType.getClass() == XHFPModelVertexType.class) {
isCompact = true;
} else if(vertexType.getClass() == SFPModelVertexType.class) {
isCompact = false;
@@ -142,6 +142,8 @@ public class ChunkBuildBuffers implements ChunkBuildBuffersExt {
if (sortTranslucent && pass.isTranslucent()) {
ChunkBufferSorter.sortStandardFormat(vertexType, buffer, bufferLen, x, y, z);
meshData.clearSlices();
meshData.setModelSlice(ModelQuadFacing.UNASSIGNED, new BufferSlice(0, bufferLen));
}
meshData.setVertexData(new VertexData(buffer, this.vertexType.getCustomVertexFormat()));
@@ -10,7 +10,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer;
import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderBuildTask;
import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderEmptyBuildTask;
import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderRebuildTask;
import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderTranslucencySortTask;
import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal;
@@ -26,6 +25,7 @@ import net.minecraft.util.ReportedException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.joml.Vector3d;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Deque;
@@ -294,7 +294,10 @@ public class ChunkBuilder<T extends ChunkGraphicsState> {
return Runtime.getRuntime().availableProcessors();
}
private void handleCompletion(CompletableFuture<ChunkBuildResult<T>> future) {
/**
* Add a completion handler to the given future task so that the result will be processed on the main thread.
*/
public void handleCompletion(CompletableFuture<ChunkBuildResult<T>> future) {
future.whenComplete((res, ex) -> {
if (ex != null) {
this.failureQueue.add(ex);
@@ -304,16 +307,6 @@ public class ChunkBuilder<T extends ChunkGraphicsState> {
});
}
/**
* Creates a rebuild task and defers it to the work queue. When the task is completed, it will be moved onto the
* completed uploads queued which will then be drained during the next available synchronization point with the
* main thread.
* @param render The render to rebuild
*/
public void deferRebuild(ChunkRenderContainer<T> render) {
handleCompletion(this.scheduleRebuildTaskAsync(render));
}
/**
* Creates a rebuild task and defers it to the work queue. When the task is completed, it will be moved onto the
* completed uploads queued which will then be drained during the next available synchronization point with the
@@ -330,16 +323,24 @@ public class ChunkBuilder<T extends ChunkGraphicsState> {
* synchronization point on the main thread.
* @param result The build task's result
*/
private void enqueueUpload(ChunkBuildResult<T> result) {
public void enqueueUpload(ChunkBuildResult<T> result) {
this.uploadQueue.add(result);
}
/**
* Schedules the rebuild task asynchronously on the worker pool, returning a future wrapping the task.
* @param render The render to rebuild
* @return a future representing the rebuild task, or null if the chunk section is empty
*/
@Nullable
public CompletableFuture<ChunkBuildResult<T>> scheduleRebuildTaskAsync(ChunkRenderContainer<T> render) {
return this.schedule(this.createRebuildTask(render));
ChunkRenderBuildTask<T> task = this.createRebuildTask(render);
if(task != null) {
return this.schedule(task);
} else {
return null;
}
}
/**
@@ -360,7 +361,7 @@ public class ChunkBuilder<T extends ChunkGraphicsState> {
ChunkRenderContext context = WorldSlice.prepare(this.world, render.getChunkPos(), this.sectionCache);
if (context == null) {
return new ChunkRenderEmptyBuildTask<>(render);
return null;
} else {
return new ChunkRenderRebuildTask<>(render, context, render.getRenderOrigin()).withCameraPosition(this.cameraPosition);
}
@@ -17,6 +17,10 @@ public class ChunkMeshData {
this.vertexData = vertexData;
}
public void clearSlices() {
this.parts.clear();
}
public void setModelSlice(ModelQuadFacing facing, BufferSlice slice) {
this.parts.put(facing, slice);
}
@@ -1,33 +0,0 @@
package me.jellysquid.mods.sodium.client.render.chunk.tasks;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer;
import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers;
import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult;
import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData;
import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal;
import me.jellysquid.mods.sodium.client.util.task.CancellationSource;
/**
* A build task which does no computation and always return an empty build result. These tasks are created whenever
* chunk meshes need to be deleted as the only way to change graphics state is to send a message to the main
* actor thread. In cases where new chunk renders are being created and scheduled, the scheduler will prefer to just
* synchronously update the render's data to an empty state to speed things along.
*/
public class ChunkRenderEmptyBuildTask<T extends ChunkGraphicsState> extends ChunkRenderBuildTask<T> {
private final ChunkRenderContainer<T> render;
public ChunkRenderEmptyBuildTask(ChunkRenderContainer<T> render) {
this.render = render;
}
@Override
public ChunkBuildResult<T> performBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, CancellationSource cancellationSource) {
return new ChunkBuildResult<>(this.render, ChunkRenderData.EMPTY);
}
@Override
public void releaseResources() {
}
}
@@ -37,6 +37,7 @@ import java.util.List;
import java.util.Random;
public class BlockRenderer {
private static final BlockPos POS_ZERO = new BlockPos(0, 0, 0);
private final Random random = new XoRoShiRoRandom();
@@ -97,9 +98,10 @@ public class BlockRenderer {
TessellatorManager.startCapturing();
final CapturingTessellator tess = (CapturingTessellator) TessellatorManager.get();
tess.startDrawingQuads();
// RenderBlocks adds the subchunk-relative coordinates as the offset, cancel it out here
tess.setOffset(pos);
// Use setTranslation rather than setOffset so that the float data written to the internal buffer
// is done in subchunk-relative coordinates
tess.setOffset(POS_ZERO);
tess.setTranslation(-pos.x, -pos.y, -pos.z);
renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z);
final List<QuadView> quads = TessellatorManager.stopCapturingToPooledQuads();
tess.resetOffset();
@@ -137,8 +137,12 @@ options.dynamic_lights_shader_force=Dynamic Lights - Forced With Shaders
options.dynamic_lights_shader_force.tooltip=Enabled - Dynamic Lights are shown even when a shader is active, Disabled - Dynamic Lights are disabled when a shader is active.
options.angelica.droppedItemLimit=Dropped Item Render Limit
options.angelica.droppedItemLimit.tooltip=The maximum number of dropped items that will be rendered. Lower values can improve performance.
options.angelica.mobSpawnerRenderDistance=Mob spawner render distance
options.angelica.mobSpawnerRenderDistance.tooltip=Render distance for the spinning mob inside mod spawners
options.angelica.itemdisplaylistcount=Item Renderer Display List Cache Size
options.angelica.itemdisplaylistcount.tooltip=The maximum number of display lists to cache in the optimized item renderer. Higher values will increase performance but increase VRAM usage.
options.angelica.sleepbeforeswap=Alternate FPS Limiter
options.angelica.sleepbeforeswap.tooltip=Switches to an alternate FPS limiter that gives more stable frametimes, in exchange for slightly more latency. Will never introduce more than one frame of latency, and has a lower impact at higher framerates.
pack.iris.select.title=Select
pack.iris.configure.title=Configure
label.iris.true=On
@@ -1,7 +1,10 @@
package com.gtnewhorizons.angelica.mixins.early.angelica;
import com.gtnewhorizons.angelica.AngelicaMod;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import com.gtnewhorizons.angelica.mixins.interfaces.IGameSettingsExt;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings;
import org.lwjgl.input.Keyboard;
@@ -14,10 +17,16 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
public class MixinMinecraft {
public abstract class MixinMinecraft {
@Shadow
public GameSettings gameSettings;
@Shadow
public abstract boolean isFramerateLimitBelowMax();
@Shadow
public abstract int getLimitFramerate();
@Unique
private long angelica$lastFrameTime = 0;
@@ -29,16 +38,38 @@ public class MixinMinecraft {
GL11.glEnable(GL11.GL_LIGHTING);
}
@Inject(
method = "func_147120_f",
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/Display;update()V", shift = At.Shift.BEFORE, remap = false)
)
private void angelica$limitFPS(CallbackInfo ci) {
if (!AngelicaConfig.sleepBeforeSwap) return;
if (isFramerateLimitBelowMax()) {
final long target = angelica$lastFrameTime + (long) (1.0 / getLimitFramerate() * 1_000_000) * 1_000;
while (target - System.nanoTime() > 100) {
Thread.yield();
}
}
}
@Inject(
method = "func_147120_f",
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/Display;update()V", shift = At.Shift.AFTER, remap = false)
)
private void angelica$trackFrametimes(CallbackInfo ci) {
if (AngelicaMod.proxy == null) return;
long time = System.nanoTime();
AngelicaMod.proxy.putFrametime(time - angelica$lastFrameTime);
angelica$lastFrameTime = time;
}
@WrapOperation(method = "runGameLoop", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/Display;sync(I)V"))
private void angelica$noopFPSLimiter(int fps, Operation<Void> original) {
if (AngelicaConfig.sleepBeforeSwap) return;
original.call(fps);
}
@Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiScreen;isShiftKeyDown()Z", shift = At.Shift.AFTER))
private void angelica$setShowFpsGraph(CallbackInfo ci) {
((IGameSettingsExt) gameSettings).angelica$setShowFpsGraph(Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU));
@@ -0,0 +1,21 @@
package com.gtnewhorizons.angelica.mixins.early.angelica.bugfixes;
import net.minecraft.client.gui.ScaledResolution;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(ScaledResolution.class)
public class MixinScaledResolution_UnicodeFix {
// Force unicode languages to use the calculated scaleFactor and not adjust it.
// Can lead to blurry text
@ModifyConstant(method = "<init>", constant = @Constant(intValue = 1, ordinal = 5))
int angelica$ScaledResolutionInit(int constant){
return 0;
}
}
@@ -0,0 +1,17 @@
package com.gtnewhorizons.angelica.mixins.early.sodium;
import com.gtnewhorizons.angelica.config.AngelicaConfig;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(TileEntityMobSpawner.class)
public class MixinTileEntityMobSpawner extends TileEntity {
@Override
public double getMaxRenderDistanceSquared() {
final double d = AngelicaConfig.mobSpawnerRenderDistance;
return d * d;
}
}